## Load libraries


suppressPackageStartupMessages({
library(ArchR)
library(rhdf5)
library(tidyverse)
library(reticulate)
library(zellkonverter)
library(Matrix)
library(dichromat)
library(Seurat)
#library(caret)
h5disableFileLocking()})
rna_seurat <- readRDS("Seurat_objects/rna_Seurat_object")
hvg <- VariableFeatures(rna_seurat)
# directory where to save the figures
plot_dir <- "/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data_new/Kathi/plots/report_chromvar/"
# get gene expression matrix
proj <- loadArchRProject("12_Ricards_peaks_ChromVar")


# get the metadata 
metadata <- as.data.frame(getCellColData(proj))

ChromVar Motif deviation scores


# get motif matrix
motifs <- getMatrixFromProject(proj, useMatrix = "MotifMatrix")
motif_mtx <- assays(motifs)[[2]]
# remove index number from TFs
tfs <- gsub("_.*", "", rownames(motifs))
rownames(motif_mtx) <- tfs

Gene activity scores

gene_scores <- getMatrixFromProject(proj, useMatrix = "GeneScoreMatrix")
gene_scores_mat <- assays(gene_scores)[[1]]
rownames(gene_scores_mat) <- rowData(gene_scores)$name
colnames(gene_scores_mat) <- colnames(gene_scores)

Deep Learning deviations

proj1 <- loadArchRProject("/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data_new/Kathi/06_deep_chromvar/")
# get motif matrix
deep_motifs <- getMatrixFromProject(proj1, useMatrix = "DeepLearningMotifs1")
deep_motif_mtx <- assays(deep_motifs)[[2]]

rownames(deep_motif_mtx) <- tolower(rownames(deep_motif_mtx))
substr(rownames(deep_motif_mtx), 1, 1) <- toupper(substr(rownames(deep_motif_mtx), 1, 1))


tfs <- rownames(deep_motif_mtx)
metadata <- colData(deep_motifs) %>% as.data.frame()

Plotting Functions

plot_score_per_celltypes <- function(tf, score_matrix, metadata_df, y_label){
  motif_n <- score_matrix[rownames(score_matrix) %in% tf, ]
  plot <- metadata_df %>% 
    mutate(!!tf := motif_n) %>%
    group_by(celltypes) %>%
    summarise(mean = mean(!!(sym(tf)))) %>%
    ggplot() +
    geom_bar(aes(x = celltypes, y = mean, fill = celltypes), stat = "identity") +
    scale_fill_manual(values = col) +
    labs(y = paste0(y_label),
         title = paste0(n)) +
    BAR_THEME
  
  return(plot)
}

scatterplot <- function(tf, score_matrix_x, score_matrix_y, metadata_df, x_label, y_label){
  motif_x <- score_matrix_x[rownames(score_matrix_x) %in% tf, ]
  motif_y <- score_matrix_y[rownames(score_matrix_y) %in% tf, ]
  plot <- metadata_df %>% 
    mutate(tf_x := motif_x, tf_y := motif_y) %>%
    group_by(celltypes) %>%
    summarise_at(vars(tf_x, tf_y), mean) %>% 
    ggplot() +
    geom_smooth(aes(x = tf_x, y = tf_y),
                formula = y ~ x, method = "lm", size =.1) +
    geom_point(aes(x = tf_x, y = tf_y, col = celltypes, size = 1)) +
    scale_color_manual(values = col) + 
    labs(title = paste0(tf), 
         x = paste0(x_label),
         y = paste0(y_label)) +
    SCATTER_THEME
    
  return(plot)
}

Plot Themes

BAR_THEME <- theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1, size = 10),
                   axis.text.y = element_text(size = 12),
                   axis.title.x = element_text(size = 15), 
                   axis.title.y = element_text(size = 15),
                   plot.title = element_text(hjust = 0.5, size = 20),
          legend.position = "none",
          panel.grid.major = element_line(colour = "grey"),   # Major grid lines
          panel.background = element_rect(fill = "white", colour = "black")) 

SCATTER_THEME <- theme(axis.text.x = element_text(size = 12),
                   axis.text.y = element_text(size = 12),
                   axis.title.x = element_text(size = 15), 
                   axis.title.y = element_text(size = 15),
                   plot.title = element_text(hjust = 0.5, size = 20),
          legend.position = "none",
          panel.grid.major = element_line(colour = "grey"),   # Major grid lines
          panel.background = element_rect(fill = "white", colour = "black")) 

Color Palette:

colPalette_celltypes = c('#532C8A',
 '#c19f70',
 '#f9decf',
 '#c9a997',
 '#B51D8D',
 '#3F84AA',
 '#9e6762',
 '#354E23',
 '#F397C0',
 '#ff891c',
 '#635547',
 '#C72228',
 '#f79083',
 '#EF4E22',
 '#989898',
 '#7F6874',
 '#8870ad',
 '#647a4f',
 '#EF5A9D',
 '#FBBE92',
 '#139992',
 '#cc7818',
 '#DFCDE4',
 '#8EC792',
 '#C594BF',
 '#C3C388',
 '#0F4A9C',
 '#FACB12',
 '#8DB5CE',
 '#1A1A1A',
 '#C9EBFB',
 '#DABE99',
 '#65A83E',
 '#005579',
 '#CDE088',
 '#f7f79e',
 '#F6BFCB')

celltypes <- (as.data.frame(getCellColData(proj)) %>% group_by(celltypes) %>% 
 summarise(n = n()))$celltypes

col <- setNames(colPalette_celltypes, celltypes)

Select a few marker genes and transcription factors:

marker_genes <- c("Lamb1",  "Sparc", "Elf5", "Ascl2", "Tfap2c", "Ttr",
                  "Apoa2", "Apoe", "Cystm1", "Emb", "Spink1",  "Krt19",
                  "Dkk1", "Grhl3", "Trp63", "Grhl2",  "Pax6", "Pax2",
                  "En1", "Foxd3", "Tfap2a", "Pax3", "Sox9",
                  "Six3", "Hesx1", "Irx3", "Hoxb9", "Cdx4",
                  "Hes3", "Hba-a2", "Hba-a1",  "Hbb-bh1", "Gata1",
                   "Gata6",
                  #"Gata6", "Gata5",
                  "Cited4",
                   "Cdh5", "Pecam1", "Anxa5", "Etv2", "Igf2",
                  "Krt8", "Krt18", "Pmp22", "Ahnak", "Bmp4", "Tbx4", "Hoxa11",
                  "Hoxa10", "Tnnt2", "Myl4",  "Myl7", "Acta2",
                  "Smarcd3", "Tcf21", "Tbx6", "Dll1", "Aldh1a2", "Tcf15",
                  "Meox1", "Tbx1", "Gbx2", "Cdx1", "Hoxb1", "Hes7", "Osr1",
                  "Mesp2", "Lefty2", "Mesp1", "Cer1",  "Chrd", 
                  "Foxa2", "Pax7", "Fgf8", "Lhx1", "Mixl1", "Otx2", "Hhex",
                   "Ifitm3", "Nkx1-2", "Eomes", "Nanog", "Utf1",
                  "Epcam", "Pou5f1" )
#"Sox2"
#"Gata2"
#"Gata4"
#  "Gata5",
#"Gata6",
# "Gsc",

Deep Learning motifs vs. cisbp motifs


markers <- c("Elf5", "Pax2", "Pax6", "Pax3", "Pax7", "Hoxb9", "Cdx4", "Hoxa11", "Hoxa10", "Tcf15", 
  "Tbx1", "Tbx6", "Mesp2", "Mesp1", "Pouf51", "Gata1", "Gata2", "Gata3", "Gata4",  "Gata6", "Sox10",
  "Sox11" ,"Sox13","Sox15","Sox17"      
  ,"Sox2" , "Sox3", "Sox30", "Sox4", "Sox5", "Sox6", "Sox9", "Klf1", "Klf3", "Klf4", "Klf5", "Klf9" )

# select only markers present in all three matrices 
markers <- markers[markers %in% rownames(deep_motif_mtx)]
markers <- markers[markers %in% rownames(motif_mtx)]
markers <- markers[markers %in% rownames(gene_scores_mat)]



for (n in markers){
  ## BAR PLOTS
  score_plot <- plot_score_per_celltypes(n, gene_scores_mat, metadata,
                                         y_label = "Gene activity score")
  ggsave(paste0(plot_dir, "score", n, ".pdf"))
  
  
  motif_plot <- plot_score_per_celltypes(n, motif_mtx, metadata, 
                                         y_label = "ChromVar scores")
  ggsave(paste0(plot_dir, "motif", n, ".pdf"))
  
  
  deep_plot <- plot_score_per_celltypes(n, deep_motif_mtx, metadata,
                                        y_label = "Deep learning ChromVar scores")
  ggsave(paste0(plot_dir, "deep", n, ".pdf"), deep_plot)
  
  
  ## SCATTER PLOTS
  scatter_motif <- scatterplot(n, gene_scores_mat, motif_mtx, metadata, 
              x_label = "Gene activity scores",
              y_label = "ChromVar scores")
  ggsave(paste0(plot_dir, "scatter_motif", n, ".pdf"), scatter_motif)

  
  scatter_deep <- scatterplot(n, gene_scores_mat, deep_motif_mtx, metadata,
              x_label = "Gene activity scores",
              y_label = "Deep learning ChromVar scores")
  ggsave(paste0(plot_dir, "scatter_deep", n, ".pdf"), scatter_deep)


  ## Combine Plots
  print(cowplot::plot_grid(score_plot, motif_plot, deep_plot,
                           scatter_motif, scatter_deep, ncol = 3))
  
  
}

ChromVar scores using cisbp


markers <- c("Lamb1",  "Sparc", "Elf5", "Ascl2", "Tfap2c", "Ttr",
                  "Apoa2", "Apoe", "Cystm1", "Emb", "Spink1",  "Krt19",
                  "Dkk1", "Grhl3", "Trp63", "Grhl2",  "Pax6", "Pax2",
                  "En1", "Foxd3", "Tfap2a", "Pax3", "Sox9",
                  "Six3", "Hesx1", "Irx3", "Hoxb9", "Cdx4",
                  "Hes3", "Hba-a2", "Hba-a1",  "Hbb-bh1", "Gata1",
                   "Gata6",
                  #"Gata6", "Gata5",
                  "Cited4",
                   "Cdh5", "Pecam1", "Anxa5", "Etv2", "Igf2",
                  "Krt8", "Krt18", "Pmp22", "Ahnak", "Bmp4", "Tbx4", "Hoxa11",
                  "Hoxa10", "Tnnt2", "Myl4",  "Myl7", "Acta2",
                  "Smarcd3", "Tcf21", "Tbx6", "Dll1", "Aldh1a2", "Tcf15",
                  "Meox1", "Tbx1", "Gbx2", "Cdx1", "Hoxb1", "Hes7", "Osr1",
                  "Mesp2", "Lefty2", "Mesp1", "Cer1",  "Chrd", 
                  "Foxa2", "Pax7", "Fgf8", "Lhx1", "Mixl1", "Otx2", "Hhex",
                   "Ifitm3", "Nkx1-2", "Eomes", "Nanog", "Utf1",
                  "Epcam", "Pou5f1" )

# select only markers prsent in both matrices
markers <- markers[markers %in% rownames(motif_mtx)]
markers <- markers[markers %in% rownames(gene_scores_mat)]

for (n in markers){
  ## BAR PLOTS
  score_plot <- plot_score_per_celltypes(n, gene_scores_mat, metadata,
                                         y_label = "Gene activity score")

  
  motif_plot <- plot_score_per_celltypes(n, motif_mtx, metadata, 
                                         y_label = "ChromVar scores")

  
  
  ## SCATTER PLOTS
  scatter_motif <- scatterplot(n, gene_scores_mat, motif_mtx, metadata, 
              x_label = "Gene activity scores",
              y_label = "ChromVar scores")


  ## Combine Plots
  print(cowplot::plot_grid(score_plot, motif_plot,
                           scatter_motif, ncol = 2))
  
  
}

GATA Factors

```#{r, fig.width=6, fig.height=6} for (n in c(“Gata1”, “Gata2”, “Gata3”, “Gata4”, “Gata5”, “Gata6”)) { print(n) # select one row for a particular gene score_n <- gene_scores_mat[rownames(gene_scores_mat) %in% n, ] # add score for this gene to metadata metadata[paste0(“score_”,n)] <- score_n # select gene expression for a particular gene expr_n <- lognorm[rownames(lognorm) %in% c(n), ] metadata[paste0(“expr_”, n)] <- expr_n

seacells_n <- sea_mtx[rownames(sea_mtx) == tfs[grepl(paste0(“^”, n), tfs)], ] sea_meta[paste0(“seacell_”, n)] <- seacells_n

# select motif z score motif_n <- motif_mtx[rownames(motif_mtx) == tfs[grepl(paste0(“^”, n), tfs)], ] metadata[paste0(“motif_”, n)] <- motif_n

# create barplots for gene scores, gene expression and motif z-score plots <- map(c(“score_”, “motif_”), function(p){ df <- metadata %>% group_by(celltypes) %>% summarise_at(vars(paste0(p, n)), funs(mean(., na.rm=TRUE))) plot <- df %>% ggplot() + geom_bar(aes(x = celltypes, y = df %>% pull(paste0(p, n)), fill = celltypes), stat = “identity”) + scale_fill_manual(values = col) + labs(title = paste0(n), x = “celltype”, y = paste0(p)) + BAR_THEME print(plot) ggsave(paste0(plot_dir, p, n, “.pdf”)) print(plot) }) sea_plot <- map(seq.int(1), function(sea){ plot <- sea_meta %>% group_by(celltypes) %>% summarise(mean = mean(!!sym(paste0(“seacell_”,n)))) %>% ggplot() + geom_bar(aes(x = celltypes, y = mean, fill = celltypes), stat = “identity”) + scale_fill_manual(values = col) + labs(title = paste0(n), y = “SEACell deviation score”) + BAR_THEME print(plot) ggsave(paste0(plot_dir, “seacell_bar_”, n, “.pdf”)) print(plot)

}) # create scatter plots for gene expression and motif z-score scatter_plots <- map(seq.int(1), function(s){ df <- metadata %>% group_by(celltypes) %>% summarise_at(vars(paste0(“motif_”, n), paste0(“score_”, n)), funs(mean(., na.rm = TRUE))) plot <- df %>% ggplot() + geom_smooth(aes(x = df %>% pull(paste0(“score_”, n)), y = df %>% pull(paste0(“motif_”, n))), formula = y ~ x, method = “lm”, size = .1) + geom_point(aes(x = df %>% pull(paste0(“score_”, n)), y = df %>% pull(paste0(“motif_”, n)), col = celltypes, size = 1)) + SCATTER_THEME + #labs(x = “Gata1 gene expression”, y = “Gata1 motif accessibility (z-score)”) + scale_color_manual(values = col) + labs(title = paste0(n), x = “gene activity score”, y = “TF-motif z-score”) print(plot) ggsave(paste0(plot_dir, “scatterPlot_”, n, “.pdf”)) print(plot) })

do.call(gridExtra::grid.arrange, c(plots, sea_plot, scatter_plots, ncol = 2)) #%>% ggsave(paste0(plot_dir, n, “.pdf”))

}


# Marker Genes

## SEACells


```#{r, fig.width=6, fig.height=6, eval = FALSE}

for (n in marker_genes) {
  print(n)
  # select one row for a particular gene
  score_n <- gene_scores_mat[rownames(gene_scores_mat) %in% c(n), ]
  # add score for this gene to metadata
  metadata[paste0("score_",n)] <- score_n
  # select gene expression for a particular gene
  expr_n <- lognorm[rownames(lognorm) %in% c(n), ]
  metadata[paste0("expr_", n)] <- expr_n
  
  
  seacells_n <- sea_mtx[rownames(sea_mtx) == tfs[grepl(paste0("^", n), tfs)], ]
  sea_meta[paste0("seacell_", n)] <- seacells_n

  # if the marker gene is a TF
  if (length(tfs[grepl(paste0("^", n), tfs)]) > 0) {
    
      # select motif z score
      motif_n <- motif_mtx[rownames(motif_mtx) ==  tfs[grepl(paste0("^", n), tfs)], ]
      metadata[paste0("motif_", n)] <- motif_n
      
      # create barplots for gene scores, gene expression and motif z-score
      plot <- map(c("score_", "motif_"), function(p){
        df <- metadata %>%
          group_by(celltypes) %>%
          summarise_at(vars(paste0(p, n)), funs(mean(., na.rm=TRUE)))
          plot <- df %>% ggplot() +
          geom_bar(aes(x = celltypes, y = df %>% pull(paste0(p, n)), 
                       fill = celltypes), stat = "identity") +
          scale_fill_manual(values = col) +
          theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
                legend.position = "none") +
          labs(title = paste0(n), x = "celltype", y = paste0(p)) +
          BAR_THEME
        print(plot)
        ggsave(paste0(plot_dir, p, n, ".pdf"))
        print(plot)
      })
      
      # create scatter plots for gene expression and motif z-score
      scatter_plots <- map(seq.int(1), function(s){
        df <- metadata %>% group_by(celltypes) %>% 
        summarise_at(vars(paste0("motif_", n), 
                          paste0("score_", n)), 
                     funs(mean(., na.rm = TRUE)))
        plot <- df %>%
          ggplot() +
          geom_smooth(aes(x = df %>% pull(paste0("score_", n)), 
                          y = df %>% pull(paste0("motif_", n))),
                      formula = y ~ x, method = "lm", size = .1) +
          geom_point(aes(x = df %>% pull(paste0("score_", n)), 
                         y = df %>% pull(paste0("motif_", n)), 
                         col = celltypes, size = 1)) +
          #labs(x = "Gata1 gene expression", y = "Gata1 motif accessibility (z-score)") +
          theme(legend.position = "none") +
          scale_color_manual(values = col) +
          labs(title = paste0(n), x = "gene activity score", y = "TF-motif z-score") +
          BAR_THEME
        print(plot)
        ggsave(paste0(plot_dir, "scatterPlot_", n, ".pdf"))
        print(plot)
      })
        sea_plot <- map(seq.int(1), function(sea){
          plot <- sea_meta %>% 
            group_by(celltypes) %>%
            summarise(mean = mean(!!sym(paste0("seacell_",n)))) %>%
            ggplot() +
            geom_bar(aes(x = celltypes, y = mean, fill = celltypes), stat = "identity") +
            scale_fill_manual(values = col) +
            theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), legend.position = "None") +#%>% print()
            labs(title = paste0(n), y = "SEACell deviation score") +
            BAR_THEME
          print(plot)
          ggsave(paste0(plot_dir, "seacell_bar_", n, ".pdf"))
          print(plot)
          
    })
      
    # if the marker gene is no TF
    } else {
      print("no")
      
      # # create barplots for gene scores, gene expression and motif z-score
      # plots <- map(c("score_"), function(p){
      #   df <- metadata %>%
      #     group_by(celltypes) %>%
      #     summarise_at(vars(paste0(p, n)), funs(mean(., na.rm=TRUE)))
      #     plot <- df %>% ggplot() +
      #     geom_bar(aes(x = celltypes, y = df %>% pull(paste0(p, n)), 
      #                  fill = celltypes), stat = "identity") +
      #     scale_fill_manual(values = col) +
      #     theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
      #           legend.position = "none") +
      #     labs(title = paste0(n), x = "celltype", y = paste0(p)) +
      #     BAR_THEME
      #   print(plot)
      #   ggsave(paste0(plot_dir, p, n, ".pdf"))
      #   print(plot)
      # 
      # })
      # 
      # # create scatter plots for gene expression and gene_score
      # scatter_plots <- map(seq.int(1), function(s){
      #   df <- metadata %>% group_by(celltypes) %>%
      #   summarise_at(vars(paste0("score_", n),
      #                     paste0("expr_", n)),
      #                funs(mean(., na.rm = TRUE)))
      #   plot <- df %>%
      #     ggplot() +
      #     geom_smooth(aes(x = df %>% pull(paste0("expr_", n)),
      #                     y = df %>% pull(paste0("score_", n))),
      #                 formula = y ~ x, method = "lm", size = .1) +
      #     geom_point(aes(x = df %>% pull(paste0("expr_", n)),
      #                    y = df %>% pull(paste0("score_", n)),
      #                    col = celltypes, size = 1)) +
      #     #labs(x = "Gata1 gene expression", y = "Gata1 motif accessibility (z-score)") +
      #     theme(legend.position = "none") +
      #     scale_color_manual(values = col)+
      #     labs(title = paste0(n), x = "gene expression", y = "gene activity score") +
      #     BAR_THEME
      #   print(plot)
      #   ggsave(paste0(plot_dir, "scatterPlot_", n, ".pdf"))
      #   print(plot)
      #})
    }

  #do.call(gridExtra::grid.arrange, c(plots, scatter_plots, ncol = 2, nrow = 2))
  # 

}

Deep learning motifs

proj1 <- loadArchRProject("/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data_new/Kathi/06_deep_chromvar/")

deep <- getMatrixFromProject(proj1, useMatrix = "DeepLearningMotifs1")
deep_matrix <- assays(deep)[[2]]

deep_matrix <- deep_matrix[, colnames(motif_mtx)]

stopifnot(all(colnames(motif_mtx) == colnames(deep_matrix)))
#test <- rownames(deep_matrix)
rownames(deep_matrix) <- tolower(rownames(deep_matrix))
substr(rownames(deep_matrix), 1, 1) <- toupper(substr(rownames(deep_matrix), 1, 1))

TFs of interest

markers <- c("Elf5", "Pax2", "Pax6", "Pax3", "Pax7", "Hoxb9", "Cdx4", "Hoxa11", "Hoxa10", "Tcf15", 
  "Tbx1", "Tbx6", "Mesp2", "Mesp1", "Pouf51", "Gata1", "Gata2", "Gata3", "Gata4",  "Gata6", "Sox10",
  "Sox11" ,"Sox13","Sox15","Sox17"      
  ,"Sox2" , "Sox3", "Sox30", "Sox4", "Sox5", "Sox6", "Sox9", "Klf1", "Klf3", "Klf4", "Klf5", "Klf9" )

markers <- markers[markers %in% rownames(deep_matrix)]

markers <- markers[markers %in% rownames(gene_scores_mat)]
markers

```#{r, fig.width=6, fig.height=6} plot_dir <- “/omics/groups/OE0533/internal/katharina/scDoRI/gastrulation_data_new/Kathi/plots/deep_ChromVar/”

for (n in markers) { print(n) # select one row for a particular gene score_n <- gene_scores_mat[rownames(gene_scores_mat) %in% n, ] # add score for this gene to metadata metadata[paste0(“score_”,n)] <- score_n # select gene expression for a particular gene # expr_n <- lognorm[rownames(lognorm) %in% c(n), ] # metadata[paste0(“expr_”, n)] <- expr_n

# seacells_n <- sea_mtx[rownames(sea_mtx) == tfs[grepl(paste0(“^”, n), tfs)], ] # sea_meta[paste0(“seacell_”, n)] <- seacells_n

# select motif z score deep_n <- deep_matrix[rownames(deep_matrix) %in% n, ] metadata[paste0(“deep_”, n)] <- deep_n

# create barplots for gene scores, gene expression and motif z-score plots <- map(c(“score_”, “deep_”), function(p){ df <- metadata %>% group_by(celltypes) %>% summarise_at(vars(paste0(p, n)), funs(mean(., na.rm=TRUE))) plot <- df %>% ggplot() + geom_bar(aes(x = celltypes, y = df %>% pull(paste0(p, n)), fill = celltypes), stat = “identity”) + scale_fill_manual(values = col) + labs(title = paste0(n), x = “celltype”, y = paste0(p)) + BAR_THEME print(plot) ggsave(paste0(plot_dir, p, n, “.pdf”)) print(plot) }) scatter_plots <- map(seq.int(1), function(s){ df <- metadata %>% group_by(celltypes) %>% summarise_at(vars(paste0(“deep_”, n), paste0(“score_”, n)), funs(mean(., na.rm = TRUE))) plot <- df %>% ggplot() + geom_smooth(aes(x = df %>% pull(paste0(“score_”, n)), y = df %>% pull(paste0(“deep_”, n))), formula = y ~ x, method = “lm”, size = .1) + geom_point(aes(x = df %>% pull(paste0(“score_”, n)), y = df %>% pull(paste0(“deep_”, n)), col = celltypes, size = 1)) + SCATTER_THEME + #labs(x = “Gata1 gene expression”, y = “Gata1 motif accessibility (z-score)”) + scale_color_manual(values = col) + labs(title = paste0(n), x = “gene activity score”, y = “TF-motif z-score (deep learning)”) print(plot) ggsave(paste0(plot_dir, “scatterPlot_”, n, “.pdf”)) print(plot) })

do.call(gridExtra::grid.arrange, c(plots, sea_plot, scatter_plots, ncol = 2)) #%>% ggsave(paste0(plot_dir, n, “.pdf”))

}



```#{r}
for (n in marker_genes) {
  print(n)
  # select one row for a particular gene
  score_n <- gene_scores_mat[rownames(gene_scores_mat) %in% c(n), ]
  # add score for this gene to metadata
  metadata[paste0("score_",n)] <- score_n
  # select gene expression for a particular gene
  expr_n <- lognorm[rownames(lognorm) %in% c(n), ]
  metadata[paste0("expr_", n)] <- expr_n
  
  
  seacells_n <- sea_mtx[rownames(sea_mtx) == tfs[grepl(paste0("^", n), tfs)], ]
  sea_meta[paste0("seacell_", n)] <- seacells_n

  # if the marker gene is a TF
  if (length(tfs[grepl(paste0("^", n), tfs)]) > 0) {
    
      # select motif z score
      motif_n <- motif_mtx[rownames(motif_mtx) ==  tfs[grepl(paste0("^", n), tfs)], ]
      metadata[paste0("motif_", n)] <- motif_n
      
      # create barplots for gene scores, gene expression and motif z-score
      plot <- map(c("score_", "motif_"), function(p){
        df <- metadata %>%
          group_by(celltypes) %>%
          summarise_at(vars(paste0(p, n)), funs(mean(., na.rm=TRUE)))
          plot <- df %>% ggplot() +
          geom_bar(aes(x = celltypes, y = df %>% pull(paste0(p, n)), 
                       fill = celltypes), stat = "identity") +
          scale_fill_manual(values = col) +
          theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
                legend.position = "none") +
          labs(title = paste0(n), x = "celltype", y = paste0(p)) +
          BAR_THEME
        print(plot)
        ggsave(paste0(plot_dir, p, n, ".pdf"))
        print(plot)
      })
      
      # create scatter plots for gene expression and motif z-score
      scatter_plots <- map(seq.int(1), function(s){
        df <- metadata %>% group_by(celltypes) %>% 
        summarise_at(vars(paste0("motif_", n), 
                          paste0("score_", n)), 
                     funs(mean(., na.rm = TRUE)))
        plot <- df %>%
          ggplot() +
          geom_smooth(aes(x = df %>% pull(paste0("score_", n)), 
                          y = df %>% pull(paste0("motif_", n))),
                      formula = y ~ x, method = "lm", size = .1) +
          geom_point(aes(x = df %>% pull(paste0("score_", n)), 
                         y = df %>% pull(paste0("motif_", n)), 
                         col = celltypes, size = 1)) +
          #labs(x = "Gata1 gene expression", y = "Gata1 motif accessibility (z-score)") +
          theme(legend.position = "none") +
          scale_color_manual(values = col) +
          labs(title = paste0(n), x = "gene activity score", y = "TF-motif z-score") +
          BAR_THEME
        print(plot)
        ggsave(paste0(plot_dir, "scatterPlot_", n, ".pdf"))
        print(plot)
      })
        sea_plot <- map(seq.int(1), function(sea){
          plot <- sea_meta %>% 
            group_by(celltypes) %>%
            summarise(mean = mean(!!sym(paste0("seacell_",n)))) %>%
            ggplot() +
            geom_bar(aes(x = celltypes, y = mean, fill = celltypes), stat = "identity") +
            scale_fill_manual(values = col) +
            theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), legend.position = "None") +#%>% print()
            labs(title = paste0(n), y = "SEACell deviation score") +
            BAR_THEME
          print(plot)
          ggsave(paste0(plot_dir, "seacell_bar_", n, ".pdf"))
          print(plot)
          
    })
      
    # if the marker gene is no TF
    } else {
      print("no")
      
      # # create barplots for gene scores, gene expression and motif z-score
      # plots <- map(c("score_"), function(p){
      #   df <- metadata %>%
      #     group_by(celltypes) %>%
      #     summarise_at(vars(paste0(p, n)), funs(mean(., na.rm=TRUE)))
      #     plot <- df %>% ggplot() +
      #     geom_bar(aes(x = celltypes, y = df %>% pull(paste0(p, n)), 
      #                  fill = celltypes), stat = "identity") +
      #     scale_fill_manual(values = col) +
      #     theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
      #           legend.position = "none") +
      #     labs(title = paste0(n), x = "celltype", y = paste0(p)) +
      #     BAR_THEME
      #   print(plot)
      #   ggsave(paste0(plot_dir, p, n, ".pdf"))
      #   print(plot)
      # 
      # })
      # 
      # # create scatter plots for gene expression and gene_score
      # scatter_plots <- map(seq.int(1), function(s){
      #   df <- metadata %>% group_by(celltypes) %>%
      #   summarise_at(vars(paste0("score_", n),
      #                     paste0("expr_", n)),
      #                funs(mean(., na.rm = TRUE)))
      #   plot <- df %>%
      #     ggplot() +
      #     geom_smooth(aes(x = df %>% pull(paste0("expr_", n)),
      #                     y = df %>% pull(paste0("score_", n))),
      #                 formula = y ~ x, method = "lm", size = .1) +
      #     geom_point(aes(x = df %>% pull(paste0("expr_", n)),
      #                    y = df %>% pull(paste0("score_", n)),
      #                    col = celltypes, size = 1)) +
      #     #labs(x = "Gata1 gene expression", y = "Gata1 motif accessibility (z-score)") +
      #     theme(legend.position = "none") +
      #     scale_color_manual(values = col)+
      #     labs(title = paste0(n), x = "gene expression", y = "gene activity score") +
      #     BAR_THEME
      #   print(plot)
      #   ggsave(paste0(plot_dir, "scatterPlot_", n, ".pdf"))
      #   print(plot)
      #})
    }

  #do.call(gridExtra::grid.arrange, c(plots, scatter_plots, ncol = 2, nrow = 2))
  # 

}

Plot gene expression, gene scores & motif z-scores:

```#{r, fig.width=10, fig.height=10}

for (n in marker_genes) { print(n) # select one row for a particular gene score_n <- gene_scores_mat[rownames(gene_scores_mat) %in% c(n), ] # add score for this gene to metadata metadata[paste0(“score_”,n)] <- score_n # select gene expression for a particular gene expr_n <- lognorm[rownames(lognorm) %in% c(n), ] metadata[paste0(“expr_”, n)] <- expr_n

seacells_n <- sea_mtx[rownames(sea_mtx) == tfs[grepl(paste0(“^”, n), tfs)], ] sea_meta[paste0(“seacell_”, n)] <- seacells_n

# if the marker gene is a TF if (length(tfs[grepl(paste0(“^”, n), tfs)]) > 0) {

  # select motif z score
  motif_n <- motif_mtx[rownames(motif_mtx) ==  tfs[grepl(paste0("^", n), tfs)], ]
  metadata[paste0("motif_", n)] <- motif_n
  
  # create barplots for gene scores, gene expression and motif z-score
  plots <- map(c("score_", "expr_", "motif_"), function(p){
    df <- metadata %>%
    group_by(celltypes) %>%
    summarise_at(vars(paste0(p, n)), funs(mean(., na.rm=TRUE)))
    df %>% ggplot() +
    geom_bar(aes(x = celltypes, y = df %>% pull(paste0(p, n)), 
                 fill = celltypes), stat = "identity") +
    scale_fill_manual(values = col) +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
          legend.position = "none") +
    labs(title = paste0(n), x = "celltype", y = paste0(p))
  })
  
  # create scatter plots for gene expression and motif z-score
  scatter_plots <- map(seq.int(1), function(s){
    df <- metadata %>% group_by(celltypes) %>% 
    summarise_at(vars(paste0("motif_", n), 
                      paste0("score_", n)), 
                 funs(mean(., na.rm = TRUE)))
    df %>%
    ggplot() +
    geom_smooth(aes(x = df %>% pull(paste0("score_", n)), 
                    y = df %>% pull(paste0("motif_", n))),
                formula = y ~ x, method = "lm", size = .1) +
    geom_point(aes(x = df %>% pull(paste0("score_", n)), 
                   y = df %>% pull(paste0("motif_", n)), 
                   col = celltypes, size = 1)) +
    #labs(x = "Gata1 gene expression", y = "Gata1 motif accessibility (z-score)") +
    theme(legend.position = "none") +
    scale_color_manual(values = col) +
    labs(title = paste0(n), x = "gene activity score", y = "TF-motif z-score")
    })
  
# if the marker gene is no TF
} else {
  
  # create barplots for gene scores, gene expression and motif z-score
  plots <- map(c("score_", "expr_"), function(p){
    df <- metadata %>%
    group_by(celltypes) %>%
    summarise_at(vars(paste0(p, n)), funs(mean(., na.rm=TRUE)))
    df %>% ggplot() +
    geom_bar(aes(x = celltypes, y = df %>% pull(paste0(p, n)), 
                 fill = celltypes), stat = "identity") +
    scale_fill_manual(values = col) +
    theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
          legend.position = "none") +
    labs(title = paste0(n), x = "celltype", y = paste0(p))

  })
  
  # create scatter plots for gene expression and gene_score
  scatter_plots <- map(seq.int(1), function(s){
    df <- metadata %>% group_by(celltypes) %>%
    summarise_at(vars(paste0("score_", n),
                      paste0("expr_", n)),
                 funs(mean(., na.rm = TRUE))) 
    df %>%
    ggplot() +
    geom_smooth(aes(x = df %>% pull(paste0("expr_", n)), 
                    y = df %>% pull(paste0("score_", n))),
                formula = y ~ x, method = "lm", size = .1) +
    geom_point(aes(x = df %>% pull(paste0("expr_", n)),
                   y = df %>% pull(paste0("score_", n)),
                   col = celltypes, size = 1)) +
    #labs(x = "Gata1 gene expression", y = "Gata1 motif accessibility (z-score)") +
    theme(legend.position = "none") +
    scale_color_manual(values = col)+
    labs(title = paste0(n), x = "gene expression", y = "gene activity score")

  })
}

do.call(gridExtra::grid.arrange, c(plots, scatter_plots, ncol = 2, nrow = 2)) #

}




```#{r, fig.width=10, fig.height=10}
p1 <- metadata %>%
  group_by(celltypes) %>%
  summarise_at(vars(Gata1), funs(median(., na.rm=TRUE))) %>% ggplot() +
  geom_bar(aes(x = celltypes, y = Gata1, fill = celltypes), stat = "identity") +
  scale_fill_manual(values = col) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), 
        legend.position = "none")

p2 <- metadata %>%
  group_by(celltypes) %>%
  summarise_at(vars(gata1_score_p2g), funs(mean(., na.rm=TRUE))) %>% ggplot() +
  geom_bar(aes(x = celltypes, y = gata1_score_p2g, fill = celltypes), stat = "identity") +
  scale_fill_manual(values = col) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), 
        legend.position = "none")


p3 <- metadata %>% group_by(celltypes) %>% 
  summarise_at(vars(gata1_z_scores, Gata1), funs(mean(., na.rm = TRUE))) %>%
  ggplot() +
  geom_smooth(aes(x = Gata1, y = gata1_z_scores), formula = y ~ x, method = "lm", size = .1) +
  geom_point(aes(x = Gata1, y = gata1_z_scores, col = celltypes, size = 1)) +
  labs(x = "Gata1 gene expression", y = "Gata1 motif accessibility (z-score)") +
  theme(legend.position = "none") +
  scale_color_manual(values = col) 

p4 <- metadata %>%
  group_by(celltypes) %>%
  summarise_at(vars(gata1_z_scores), funs(mean(., na.rm=TRUE))) %>% ggplot() +
  geom_bar(aes(x = celltypes, y = gata1_z_scores, fill = celltypes), stat = "identity") +
  scale_fill_manual(values = col) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), 
        legend.position = "none")

cowplot::plot_grid(p1, p2, p3, p4)

p1 <- metadata %>%
  group_by(celltypes) %>%
  summarise_at(vars(Sox9), funs(mean(., na.rm=TRUE))) %>% ggplot() +
  geom_bar(aes(x = celltypes, y = Sox9, fill = celltypes), stat = "identity") +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1),
        legend.position = "none") +
  scale_fill_manual(values = col)



p2 <- metadata %>%
  group_by(celltypes) %>%
  summarise_at(vars(sox9_z_scores), funs(mean(., na.rm=TRUE))) %>% ggplot() +
  geom_bar(aes(x = celltypes, y = sox9_z_scores, fill = celltypes), stat = "identity") +
  scale_fill_manual(values = col) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), 
        legend.position = "none")

p3 <- metadata %>%
  group_by(celltypes) %>%
  summarise_at(vars(sox9_score_p2g), funs(mean(., na.rm=TRUE))) %>% ggplot() +
  geom_bar(aes(x = celltypes, y = sox9_score_p2g, fill = celltypes), stat = "identity") +
  scale_fill_manual(values = col) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust=1), 
        legend.position = "none")


p4 <- metadata %>% group_by(celltypes) %>% 
  summarise_at(vars(sox9_z_scores, Sox9), funs(mean(., na.rm = TRUE))) %>%
  ggplot() +
  geom_smooth(aes(x = Sox9, y = sox9_z_scores), formula = y ~ x, method = "lm", size = .1) +
  geom_point(aes(x = Sox9, y = sox9_z_scores, col = celltypes, size = 1)) +
  labs(x = "Gata1 gene expression", y = "Gata1 motif accessibility (z-score)") +
  theme(legend.position = "none") +
  scale_color_manual(values = col) 

cowplot::plot_grid(p1, p2, p3, p4)
LS0tCnRpdGxlOiAiMTRfQmFycGxvdHMiCm91dHB1dDogCiAgaHRtbF9kb2N1bWVudDoKICAgIHRvYzogdHJ1ZQogICAgdG9jX2RlcHRoOiA1CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdGhlbWU6IGNvc21vCiAgICBoaWdobGlnaHQ6IHRleHRtYXRlCi0tLQoKPHN0eWxlPgpib2R5IHsKdGV4dC1hbGlnbjoganVzdGlmeX0KPC9zdHlsZT4KCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoY2FjaGUgPSBGQUxTRSwgYXV0b2RlcCA9IFRSVUUsIAogICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2UgPSBUUlVFLCBtZXNzYWdlID0gRkFMU0UpCmtuaXRyOjpvcHRzX2tuaXQkc2V0KHJvb3QuZGlyID0gIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvIikKc2V0d2QoIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGEvIikKCnNldC5zZWVkKDEpCmBgYAoKICAKYGBge3J9CiMjIExvYWQgbGlicmFyaWVzCgoKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKbGlicmFyeShBcmNoUikKbGlicmFyeShyaGRmNSkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkocmV0aWN1bGF0ZSkKbGlicmFyeSh6ZWxsa29udmVydGVyKQpsaWJyYXJ5KE1hdHJpeCkKbGlicmFyeShkaWNocm9tYXQpCmxpYnJhcnkoU2V1cmF0KQojbGlicmFyeShjYXJldCkKaDVkaXNhYmxlRmlsZUxvY2tpbmcoKX0pCmBgYAoKYGBgI3tyfQpybmFfc2V1cmF0IDwtIHJlYWRSRFMoIlNldXJhdF9vYmplY3RzL3JuYV9TZXVyYXRfb2JqZWN0IikKaHZnIDwtIFZhcmlhYmxlRmVhdHVyZXMocm5hX3NldXJhdCkKYGBgCmBgYHtyfQojIGRpcmVjdG9yeSB3aGVyZSB0byBzYXZlIHRoZSBmaWd1cmVzCnBsb3RfZGlyIDwtICIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhX25ldy9LYXRoaS9wbG90cy9yZXBvcnRfY2hyb212YXIvIgpgYGAKCgoKCmBgYHtyfQojIGdldCBnZW5lIGV4cHJlc3Npb24gbWF0cml4CnByb2ogPC0gbG9hZEFyY2hSUHJvamVjdCgiMTJfUmljYXJkc19wZWFrc19DaHJvbVZhciIpCgoKIyBnZXQgdGhlIG1ldGFkYXRhIAptZXRhZGF0YSA8LSBhcy5kYXRhLmZyYW1lKGdldENlbGxDb2xEYXRhKHByb2opKQpgYGAKCiMjIyBDaHJvbVZhciBNb3RpZiBkZXZpYXRpb24gc2NvcmVzCgpgYGB7cn0KCiMgZ2V0IG1vdGlmIG1hdHJpeAptb3RpZnMgPC0gZ2V0TWF0cml4RnJvbVByb2plY3QocHJvaiwgdXNlTWF0cml4ID0gIk1vdGlmTWF0cml4IikKbW90aWZfbXR4IDwtIGFzc2F5cyhtb3RpZnMpW1syXV0KIyByZW1vdmUgaW5kZXggbnVtYmVyIGZyb20gVEZzCnRmcyA8LSBnc3ViKCJfLioiLCAiIiwgcm93bmFtZXMobW90aWZzKSkKcm93bmFtZXMobW90aWZfbXR4KSA8LSB0ZnMKYGBgCgoKCiMjIyBHZW5lIGFjdGl2aXR5IHNjb3JlcwoKCmBgYHtyfQpnZW5lX3Njb3JlcyA8LSBnZXRNYXRyaXhGcm9tUHJvamVjdChwcm9qLCB1c2VNYXRyaXggPSAiR2VuZVNjb3JlTWF0cml4IikKZ2VuZV9zY29yZXNfbWF0IDwtIGFzc2F5cyhnZW5lX3Njb3JlcylbWzFdXQpyb3duYW1lcyhnZW5lX3Njb3Jlc19tYXQpIDwtIHJvd0RhdGEoZ2VuZV9zY29yZXMpJG5hbWUKY29sbmFtZXMoZ2VuZV9zY29yZXNfbWF0KSA8LSBjb2xuYW1lcyhnZW5lX3Njb3JlcykKCmBgYAoKCgoKIyMjIERlZXAgTGVhcm5pbmcgZGV2aWF0aW9ucwoKYGBge3J9CnByb2oxIDwtIGxvYWRBcmNoUlByb2plY3QoIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGFfbmV3L0thdGhpLzA2X2RlZXBfY2hyb212YXIvIikKIyBnZXQgbW90aWYgbWF0cml4CmRlZXBfbW90aWZzIDwtIGdldE1hdHJpeEZyb21Qcm9qZWN0KHByb2oxLCB1c2VNYXRyaXggPSAiRGVlcExlYXJuaW5nTW90aWZzMSIpCmRlZXBfbW90aWZfbXR4IDwtIGFzc2F5cyhkZWVwX21vdGlmcylbWzJdXQoKcm93bmFtZXMoZGVlcF9tb3RpZl9tdHgpIDwtIHRvbG93ZXIocm93bmFtZXMoZGVlcF9tb3RpZl9tdHgpKQpzdWJzdHIocm93bmFtZXMoZGVlcF9tb3RpZl9tdHgpLCAxLCAxKSA8LSB0b3VwcGVyKHN1YnN0cihyb3duYW1lcyhkZWVwX21vdGlmX210eCksIDEsIDEpKQoKCnRmcyA8LSByb3duYW1lcyhkZWVwX21vdGlmX210eCkKbWV0YWRhdGEgPC0gY29sRGF0YShkZWVwX21vdGlmcykgJT4lIGFzLmRhdGEuZnJhbWUoKQoKYGBgCgoKCgoKIyMgUGxvdHRpbmcgRnVuY3Rpb25zCgpgYGB7cn0KcGxvdF9zY29yZV9wZXJfY2VsbHR5cGVzIDwtIGZ1bmN0aW9uKHRmLCBzY29yZV9tYXRyaXgsIG1ldGFkYXRhX2RmLCB5X2xhYmVsKXsKICBtb3RpZl9uIDwtIHNjb3JlX21hdHJpeFtyb3duYW1lcyhzY29yZV9tYXRyaXgpICVpbiUgdGYsIF0KICBwbG90IDwtIG1ldGFkYXRhX2RmICU+JSAKICAgIG11dGF0ZSghIXRmIDo9IG1vdGlmX24pICU+JQogICAgZ3JvdXBfYnkoY2VsbHR5cGVzKSAlPiUKICAgIHN1bW1hcmlzZShtZWFuID0gbWVhbighIShzeW0odGYpKSkpICU+JQogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9iYXIoYWVzKHggPSBjZWxsdHlwZXMsIHkgPSBtZWFuLCBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbCkgKwogICAgbGFicyh5ID0gcGFzdGUwKHlfbGFiZWwpLAogICAgICAgICB0aXRsZSA9IHBhc3RlMChuKSkgKwogICAgQkFSX1RIRU1FCiAgCiAgcmV0dXJuKHBsb3QpCn0KCnNjYXR0ZXJwbG90IDwtIGZ1bmN0aW9uKHRmLCBzY29yZV9tYXRyaXhfeCwgc2NvcmVfbWF0cml4X3ksIG1ldGFkYXRhX2RmLCB4X2xhYmVsLCB5X2xhYmVsKXsKICBtb3RpZl94IDwtIHNjb3JlX21hdHJpeF94W3Jvd25hbWVzKHNjb3JlX21hdHJpeF94KSAlaW4lIHRmLCBdCiAgbW90aWZfeSA8LSBzY29yZV9tYXRyaXhfeVtyb3duYW1lcyhzY29yZV9tYXRyaXhfeSkgJWluJSB0ZiwgXQogIHBsb3QgPC0gbWV0YWRhdGFfZGYgJT4lIAogICAgbXV0YXRlKHRmX3ggOj0gbW90aWZfeCwgdGZfeSA6PSBtb3RpZl95KSAlPiUKICAgIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lCiAgICBzdW1tYXJpc2VfYXQodmFycyh0Zl94LCB0Zl95KSwgbWVhbikgJT4lIAogICAgZ2dwbG90KCkgKwogICAgZ2VvbV9zbW9vdGgoYWVzKHggPSB0Zl94LCB5ID0gdGZfeSksCiAgICAgICAgICAgICAgICBmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsbSIsIHNpemUgPS4xKSArCiAgICBnZW9tX3BvaW50KGFlcyh4ID0gdGZfeCwgeSA9IHRmX3ksIGNvbCA9IGNlbGx0eXBlcywgc2l6ZSA9IDEpKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sKSArIAogICAgbGFicyh0aXRsZSA9IHBhc3RlMCh0ZiksIAogICAgICAgICB4ID0gcGFzdGUwKHhfbGFiZWwpLAogICAgICAgICB5ID0gcGFzdGUwKHlfbGFiZWwpKSArCiAgICBTQ0FUVEVSX1RIRU1FCiAgICAKICByZXR1cm4ocGxvdCkKfQoKYGBgCgoKIyMjIFBsb3QgVGhlbWVzCgpgYGB7cn0KQkFSX1RIRU1FIDwtIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xLCBzaXplID0gMTApLAogICAgICAgICAgICAgICAgICAgYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLCAKICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTUpLAogICAgICAgICAgICAgICAgICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgc2l6ZSA9IDIwKSwKICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICAgIHBhbmVsLmdyaWQubWFqb3IgPSBlbGVtZW50X2xpbmUoY29sb3VyID0gImdyZXkiKSwgICAjIE1ham9yIGdyaWQgbGluZXMKICAgICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJ3aGl0ZSIsIGNvbG91ciA9ICJibGFjayIpKSAKClNDQVRURVJfVEhFTUUgPC0gdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSwKICAgICAgICAgICAgICAgICAgIGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMiksCiAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwgCiAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDE1KSwKICAgICAgICAgICAgICAgICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIHNpemUgPSAyMCksCiAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG91ciA9ICJncmV5IiksICAgIyBNYWpvciBncmlkIGxpbmVzCiAgICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAid2hpdGUiLCBjb2xvdXIgPSAiYmxhY2siKSkgCmBgYAoKCiMjIyBDb2xvciBQYWxldHRlOgoKYGBge3J9CmNvbFBhbGV0dGVfY2VsbHR5cGVzID0gYygnIzUzMkM4QScsCiAnI2MxOWY3MCcsCiAnI2Y5ZGVjZicsCiAnI2M5YTk5NycsCiAnI0I1MUQ4RCcsCiAnIzNGODRBQScsCiAnIzllNjc2MicsCiAnIzM1NEUyMycsCiAnI0YzOTdDMCcsCiAnI2ZmODkxYycsCiAnIzYzNTU0NycsCiAnI0M3MjIyOCcsCiAnI2Y3OTA4MycsCiAnI0VGNEUyMicsCiAnIzk4OTg5OCcsCiAnIzdGNjg3NCcsCiAnIzg4NzBhZCcsCiAnIzY0N2E0ZicsCiAnI0VGNUE5RCcsCiAnI0ZCQkU5MicsCiAnIzEzOTk5MicsCiAnI2NjNzgxOCcsCiAnI0RGQ0RFNCcsCiAnIzhFQzc5MicsCiAnI0M1OTRCRicsCiAnI0MzQzM4OCcsCiAnIzBGNEE5QycsCiAnI0ZBQ0IxMicsCiAnIzhEQjVDRScsCiAnIzFBMUExQScsCiAnI0M5RUJGQicsCiAnI0RBQkU5OScsCiAnIzY1QTgzRScsCiAnIzAwNTU3OScsCiAnI0NERTA4OCcsCiAnI2Y3Zjc5ZScsCiAnI0Y2QkZDQicpCgpjZWxsdHlwZXMgPC0gKGFzLmRhdGEuZnJhbWUoZ2V0Q2VsbENvbERhdGEocHJvaikpICU+JSBncm91cF9ieShjZWxsdHlwZXMpICU+JSAKIHN1bW1hcmlzZShuID0gbigpKSkkY2VsbHR5cGVzCgpjb2wgPC0gc2V0TmFtZXMoY29sUGFsZXR0ZV9jZWxsdHlwZXMsIGNlbGx0eXBlcykKYGBgCgoKU2VsZWN0IGEgZmV3IG1hcmtlciBnZW5lcyBhbmQgdHJhbnNjcmlwdGlvbiBmYWN0b3JzOgpgYGB7cn0KbWFya2VyX2dlbmVzIDwtIGMoIkxhbWIxIiwgICJTcGFyYyIsICJFbGY1IiwgIkFzY2wyIiwgIlRmYXAyYyIsICJUdHIiLAogICAgICAgICAgICAgICAgICAiQXBvYTIiLCAiQXBvZSIsICJDeXN0bTEiLCAiRW1iIiwgIlNwaW5rMSIsICAiS3J0MTkiLAogICAgICAgICAgICAgICAgICAiRGtrMSIsICJHcmhsMyIsICJUcnA2MyIsICJHcmhsMiIsICAiUGF4NiIsICJQYXgyIiwKICAgICAgICAgICAgICAgICAgIkVuMSIsICJGb3hkMyIsICJUZmFwMmEiLCAiUGF4MyIsICJTb3g5IiwKICAgICAgICAgICAgICAgICAgIlNpeDMiLCAiSGVzeDEiLCAiSXJ4MyIsICJIb3hiOSIsICJDZHg0IiwKICAgICAgICAgICAgICAgICAgIkhlczMiLCAiSGJhLWEyIiwgIkhiYS1hMSIsICAiSGJiLWJoMSIsICJHYXRhMSIsCiAgICAgICAgICAgICAgICAgICAiR2F0YTYiLAogICAgICAgICAgICAgICAgICAjIkdhdGE2IiwgIkdhdGE1IiwKICAgICAgICAgICAgICAgICAgIkNpdGVkNCIsCiAgICAgICAgICAgICAgICAgICAiQ2RoNSIsICJQZWNhbTEiLCAiQW54YTUiLCAiRXR2MiIsICJJZ2YyIiwKICAgICAgICAgICAgICAgICAgIktydDgiLCAiS3J0MTgiLCAiUG1wMjIiLCAiQWhuYWsiLCAiQm1wNCIsICJUYng0IiwgIkhveGExMSIsCiAgICAgICAgICAgICAgICAgICJIb3hhMTAiLCAiVG5udDIiLCAiTXlsNCIsICAiTXlsNyIsICJBY3RhMiIsCiAgICAgICAgICAgICAgICAgICJTbWFyY2QzIiwgIlRjZjIxIiwgIlRieDYiLCAiRGxsMSIsICJBbGRoMWEyIiwgIlRjZjE1IiwKICAgICAgICAgICAgICAgICAgIk1lb3gxIiwgIlRieDEiLCAiR2J4MiIsICJDZHgxIiwgIkhveGIxIiwgIkhlczciLCAiT3NyMSIsCiAgICAgICAgICAgICAgICAgICJNZXNwMiIsICJMZWZ0eTIiLCAiTWVzcDEiLCAiQ2VyMSIsICAiQ2hyZCIsIAogICAgICAgICAgICAgICAgICAiRm94YTIiLCAiUGF4NyIsICJGZ2Y4IiwgIkxoeDEiLCAiTWl4bDEiLCAiT3R4MiIsICJIaGV4IiwKICAgICAgICAgICAgICAgICAgICJJZml0bTMiLCAiTmt4MS0yIiwgIkVvbWVzIiwgIk5hbm9nIiwgIlV0ZjEiLAogICAgICAgICAgICAgICAgICAiRXBjYW0iLCAiUG91NWYxIiApCiMiU294MiIKIyJHYXRhMiIKIyJHYXRhNCIKIyAgIkdhdGE1IiwKIyJHYXRhNiIsCiMgIkdzYyIsCmBgYAoKIyMgRGVlcCBMZWFybmluZyBtb3RpZnMgdnMuIGNpc2JwIG1vdGlmcwoKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xNX0KCm1hcmtlcnMgPC0gYygiRWxmNSIsICJQYXgyIiwgIlBheDYiLCAiUGF4MyIsICJQYXg3IiwgIkhveGI5IiwgIkNkeDQiLCAiSG94YTExIiwgIkhveGExMCIsICJUY2YxNSIsIAogICJUYngxIiwgIlRieDYiLCAiTWVzcDIiLCAiTWVzcDEiLCAiUG91ZjUxIiwgIkdhdGExIiwgIkdhdGEyIiwgIkdhdGEzIiwgIkdhdGE0IiwgICJHYXRhNiIsICJTb3gxMCIsCiAgIlNveDExIiAsIlNveDEzIiwiU294MTUiLCJTb3gxNyIgICAgICAKICAsIlNveDIiICwgIlNveDMiLCAiU294MzAiLCAiU294NCIsICJTb3g1IiwgIlNveDYiLCAiU294OSIsICJLbGYxIiwgIktsZjMiLCAiS2xmNCIsICJLbGY1IiwgIktsZjkiICkKCiMgc2VsZWN0IG9ubHkgbWFya2VycyBwcmVzZW50IGluIGFsbCB0aHJlZSBtYXRyaWNlcyAKbWFya2VycyA8LSBtYXJrZXJzW21hcmtlcnMgJWluJSByb3duYW1lcyhkZWVwX21vdGlmX210eCldCm1hcmtlcnMgPC0gbWFya2Vyc1ttYXJrZXJzICVpbiUgcm93bmFtZXMobW90aWZfbXR4KV0KbWFya2VycyA8LSBtYXJrZXJzW21hcmtlcnMgJWluJSByb3duYW1lcyhnZW5lX3Njb3Jlc19tYXQpXQoKCgpmb3IgKG4gaW4gbWFya2Vycyl7CiAgIyMgQkFSIFBMT1RTCiAgc2NvcmVfcGxvdCA8LSBwbG90X3Njb3JlX3Blcl9jZWxsdHlwZXMobiwgZ2VuZV9zY29yZXNfbWF0LCBtZXRhZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2xhYmVsID0gIkdlbmUgYWN0aXZpdHkgc2NvcmUiKQogIGdnc2F2ZShwYXN0ZTAocGxvdF9kaXIsICJzY29yZSIsIG4sICIucGRmIikpCiAgCiAgCiAgbW90aWZfcGxvdCA8LSBwbG90X3Njb3JlX3Blcl9jZWxsdHlwZXMobiwgbW90aWZfbXR4LCBtZXRhZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeV9sYWJlbCA9ICJDaHJvbVZhciBzY29yZXMiKQogIGdnc2F2ZShwYXN0ZTAocGxvdF9kaXIsICJtb3RpZiIsIG4sICIucGRmIikpCiAgCiAgCiAgZGVlcF9wbG90IDwtIHBsb3Rfc2NvcmVfcGVyX2NlbGx0eXBlcyhuLCBkZWVwX21vdGlmX210eCwgbWV0YWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2xhYmVsID0gIkRlZXAgbGVhcm5pbmcgQ2hyb21WYXIgc2NvcmVzIikKICBnZ3NhdmUocGFzdGUwKHBsb3RfZGlyLCAiZGVlcCIsIG4sICIucGRmIiksIGRlZXBfcGxvdCkKICAKICAKICAjIyBTQ0FUVEVSIFBMT1RTCiAgc2NhdHRlcl9tb3RpZiA8LSBzY2F0dGVycGxvdChuLCBnZW5lX3Njb3Jlc19tYXQsIG1vdGlmX210eCwgbWV0YWRhdGEsIAogICAgICAgICAgICAgIHhfbGFiZWwgPSAiR2VuZSBhY3Rpdml0eSBzY29yZXMiLAogICAgICAgICAgICAgIHlfbGFiZWwgPSAiQ2hyb21WYXIgc2NvcmVzIikKICBnZ3NhdmUocGFzdGUwKHBsb3RfZGlyLCAic2NhdHRlcl9tb3RpZiIsIG4sICIucGRmIiksIHNjYXR0ZXJfbW90aWYpCgogIAogIHNjYXR0ZXJfZGVlcCA8LSBzY2F0dGVycGxvdChuLCBnZW5lX3Njb3Jlc19tYXQsIGRlZXBfbW90aWZfbXR4LCBtZXRhZGF0YSwKICAgICAgICAgICAgICB4X2xhYmVsID0gIkdlbmUgYWN0aXZpdHkgc2NvcmVzIiwKICAgICAgICAgICAgICB5X2xhYmVsID0gIkRlZXAgbGVhcm5pbmcgQ2hyb21WYXIgc2NvcmVzIikKICBnZ3NhdmUocGFzdGUwKHBsb3RfZGlyLCAic2NhdHRlcl9kZWVwIiwgbiwgIi5wZGYiKSwgc2NhdHRlcl9kZWVwKQoKCiAgIyMgQ29tYmluZSBQbG90cwogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChzY29yZV9wbG90LCBtb3RpZl9wbG90LCBkZWVwX3Bsb3QsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHNjYXR0ZXJfbW90aWYsIHNjYXR0ZXJfZGVlcCwgbmNvbCA9IDMpKQogIAogIAp9CgoKYGBgCgojIyBDaHJvbVZhciBzY29yZXMgdXNpbmcgY2lzYnAKCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTV9CgptYXJrZXJzIDwtIGMoIkxhbWIxIiwgICJTcGFyYyIsICJFbGY1IiwgIkFzY2wyIiwgIlRmYXAyYyIsICJUdHIiLAogICAgICAgICAgICAgICAgICAiQXBvYTIiLCAiQXBvZSIsICJDeXN0bTEiLCAiRW1iIiwgIlNwaW5rMSIsICAiS3J0MTkiLAogICAgICAgICAgICAgICAgICAiRGtrMSIsICJHcmhsMyIsICJUcnA2MyIsICJHcmhsMiIsICAiUGF4NiIsICJQYXgyIiwKICAgICAgICAgICAgICAgICAgIkVuMSIsICJGb3hkMyIsICJUZmFwMmEiLCAiUGF4MyIsICJTb3g5IiwKICAgICAgICAgICAgICAgICAgIlNpeDMiLCAiSGVzeDEiLCAiSXJ4MyIsICJIb3hiOSIsICJDZHg0IiwKICAgICAgICAgICAgICAgICAgIkhlczMiLCAiSGJhLWEyIiwgIkhiYS1hMSIsICAiSGJiLWJoMSIsICJHYXRhMSIsCiAgICAgICAgICAgICAgICAgICAiR2F0YTYiLAogICAgICAgICAgICAgICAgICAjIkdhdGE2IiwgIkdhdGE1IiwKICAgICAgICAgICAgICAgICAgIkNpdGVkNCIsCiAgICAgICAgICAgICAgICAgICAiQ2RoNSIsICJQZWNhbTEiLCAiQW54YTUiLCAiRXR2MiIsICJJZ2YyIiwKICAgICAgICAgICAgICAgICAgIktydDgiLCAiS3J0MTgiLCAiUG1wMjIiLCAiQWhuYWsiLCAiQm1wNCIsICJUYng0IiwgIkhveGExMSIsCiAgICAgICAgICAgICAgICAgICJIb3hhMTAiLCAiVG5udDIiLCAiTXlsNCIsICAiTXlsNyIsICJBY3RhMiIsCiAgICAgICAgICAgICAgICAgICJTbWFyY2QzIiwgIlRjZjIxIiwgIlRieDYiLCAiRGxsMSIsICJBbGRoMWEyIiwgIlRjZjE1IiwKICAgICAgICAgICAgICAgICAgIk1lb3gxIiwgIlRieDEiLCAiR2J4MiIsICJDZHgxIiwgIkhveGIxIiwgIkhlczciLCAiT3NyMSIsCiAgICAgICAgICAgICAgICAgICJNZXNwMiIsICJMZWZ0eTIiLCAiTWVzcDEiLCAiQ2VyMSIsICAiQ2hyZCIsIAogICAgICAgICAgICAgICAgICAiRm94YTIiLCAiUGF4NyIsICJGZ2Y4IiwgIkxoeDEiLCAiTWl4bDEiLCAiT3R4MiIsICJIaGV4IiwKICAgICAgICAgICAgICAgICAgICJJZml0bTMiLCAiTmt4MS0yIiwgIkVvbWVzIiwgIk5hbm9nIiwgIlV0ZjEiLAogICAgICAgICAgICAgICAgICAiRXBjYW0iLCAiUG91NWYxIiApCgojIHNlbGVjdCBvbmx5IG1hcmtlcnMgcHJzZW50IGluIGJvdGggbWF0cmljZXMKbWFya2VycyA8LSBtYXJrZXJzW21hcmtlcnMgJWluJSByb3duYW1lcyhtb3RpZl9tdHgpXQptYXJrZXJzIDwtIG1hcmtlcnNbbWFya2VycyAlaW4lIHJvd25hbWVzKGdlbmVfc2NvcmVzX21hdCldCgpmb3IgKG4gaW4gbWFya2Vycyl7CiAgIyMgQkFSIFBMT1RTCiAgc2NvcmVfcGxvdCA8LSBwbG90X3Njb3JlX3Blcl9jZWxsdHlwZXMobiwgZ2VuZV9zY29yZXNfbWF0LCBtZXRhZGF0YSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2xhYmVsID0gIkdlbmUgYWN0aXZpdHkgc2NvcmUiKQoKICAKICBtb3RpZl9wbG90IDwtIHBsb3Rfc2NvcmVfcGVyX2NlbGx0eXBlcyhuLCBtb3RpZl9tdHgsIG1ldGFkYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5X2xhYmVsID0gIkNocm9tVmFyIHNjb3JlcyIpCgogIAogIAogICMjIFNDQVRURVIgUExPVFMKICBzY2F0dGVyX21vdGlmIDwtIHNjYXR0ZXJwbG90KG4sIGdlbmVfc2NvcmVzX21hdCwgbW90aWZfbXR4LCBtZXRhZGF0YSwgCiAgICAgICAgICAgICAgeF9sYWJlbCA9ICJHZW5lIGFjdGl2aXR5IHNjb3JlcyIsCiAgICAgICAgICAgICAgeV9sYWJlbCA9ICJDaHJvbVZhciBzY29yZXMiKQoKCiAgIyMgQ29tYmluZSBQbG90cwogIHByaW50KGNvd3Bsb3Q6OnBsb3RfZ3JpZChzY29yZV9wbG90LCBtb3RpZl9wbG90LAogICAgICAgICAgICAgICAgICAgICAgICAgICBzY2F0dGVyX21vdGlmLCBuY29sID0gMikpCiAgCiAgCn0KYGBgCgoKCgojIEdBVEEgRmFjdG9ycwoKYGBgI3tyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpmb3IgKG4gaW4gYygiR2F0YTEiLCAiR2F0YTIiLCAiR2F0YTMiLCAiR2F0YTQiLCAiR2F0YTUiLCAiR2F0YTYiKSkgewogIHByaW50KG4pCiAgIyBzZWxlY3Qgb25lIHJvdyBmb3IgYSBwYXJ0aWN1bGFyIGdlbmUKICBzY29yZV9uIDwtIGdlbmVfc2NvcmVzX21hdFtyb3duYW1lcyhnZW5lX3Njb3Jlc19tYXQpICVpbiUgIG4sIF0KICAjIGFkZCBzY29yZSBmb3IgdGhpcyBnZW5lIHRvIG1ldGFkYXRhCiAgbWV0YWRhdGFbcGFzdGUwKCJzY29yZV8iLG4pXSA8LSBzY29yZV9uCiAgIyBzZWxlY3QgZ2VuZSBleHByZXNzaW9uIGZvciBhIHBhcnRpY3VsYXIgZ2VuZQogIGV4cHJfbiA8LSBsb2dub3JtW3Jvd25hbWVzKGxvZ25vcm0pICVpbiUgYyhuKSwgXQogIG1ldGFkYXRhW3Bhc3RlMCgiZXhwcl8iLCBuKV0gPC0gZXhwcl9uCiAgCiAgCiAgc2VhY2VsbHNfbiA8LSBzZWFfbXR4W3Jvd25hbWVzKHNlYV9tdHgpID09IHRmc1tncmVwbChwYXN0ZTAoIl4iLCBuKSwgdGZzKV0sIF0KICBzZWFfbWV0YVtwYXN0ZTAoInNlYWNlbGxfIiwgbildIDwtIHNlYWNlbGxzX24KCiAgIyBzZWxlY3QgbW90aWYgeiBzY29yZQogIG1vdGlmX24gPC0gbW90aWZfbXR4W3Jvd25hbWVzKG1vdGlmX210eCkgPT0gIHRmc1tncmVwbChwYXN0ZTAoIl4iLCBuKSwgdGZzKV0sIF0KICBtZXRhZGF0YVtwYXN0ZTAoIm1vdGlmXyIsIG4pXSA8LSBtb3RpZl9uCiAgCiAgIyBjcmVhdGUgYmFycGxvdHMgZm9yIGdlbmUgc2NvcmVzLCBnZW5lIGV4cHJlc3Npb24gYW5kIG1vdGlmIHotc2NvcmUKICBwbG90cyA8LSBtYXAoYygic2NvcmVfIiwgIm1vdGlmXyIpLCBmdW5jdGlvbihwKXsKICAgIGRmIDwtIG1ldGFkYXRhICU+JQogICAgZ3JvdXBfYnkoY2VsbHR5cGVzKSAlPiUKICAgIHN1bW1hcmlzZV9hdCh2YXJzKHBhc3RlMChwLCBuKSksIGZ1bnMobWVhbiguLCBuYS5ybT1UUlVFKSkpCiAgICBwbG90IDwtIGRmICU+JSBnZ3Bsb3QoKSArCiAgICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IGRmICU+JSBwdWxsKHBhc3RlMChwLCBuKSksIAogICAgICAgICAgICAgICAgIGZpbGwgPSBjZWxsdHlwZXMpLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG4pLCB4ID0gImNlbGx0eXBlIiwgeSA9IHBhc3RlMChwKSkgKwogICAgQkFSX1RIRU1FCiAgICBwcmludChwbG90KQogICAgZ2dzYXZlKHBhc3RlMChwbG90X2RpciwgcCwgbiwgIi5wZGYiKSkKICAgIHByaW50KHBsb3QpCiAgfSkKICBzZWFfcGxvdCA8LSBtYXAoc2VxLmludCgxKSwgZnVuY3Rpb24oc2VhKXsKICAgIHBsb3QgPC0gc2VhX21ldGEgJT4lIAogICAgZ3JvdXBfYnkoY2VsbHR5cGVzKSAlPiUKICAgIHN1bW1hcmlzZShtZWFuID0gbWVhbighIXN5bShwYXN0ZTAoInNlYWNlbGxfIixuKSkpKSAlPiUKICAgIGdncGxvdCgpICsKICAgIGdlb21fYmFyKGFlcyh4ID0gY2VsbHR5cGVzLCB5ID0gbWVhbiwgZmlsbCA9IGNlbGx0eXBlcyksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAobiksIHkgPSAiU0VBQ2VsbCBkZXZpYXRpb24gc2NvcmUiKSArCiAgICBCQVJfVEhFTUUKICAgIHByaW50KHBsb3QpCiAgICBnZ3NhdmUocGFzdGUwKHBsb3RfZGlyLCAic2VhY2VsbF9iYXJfIiwgbiwgIi5wZGYiKSkKICAgIHByaW50KHBsb3QpCiAgICAKICB9KQogICMgY3JlYXRlIHNjYXR0ZXIgcGxvdHMgZm9yIGdlbmUgZXhwcmVzc2lvbiBhbmQgbW90aWYgei1zY29yZQogIHNjYXR0ZXJfcGxvdHMgPC0gbWFwKHNlcS5pbnQoMSksIGZ1bmN0aW9uKHMpewogICAgZGYgPC0gbWV0YWRhdGEgJT4lIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lIAogICAgc3VtbWFyaXNlX2F0KHZhcnMocGFzdGUwKCJtb3RpZl8iLCBuKSwgCiAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoInNjb3JlXyIsIG4pKSwgCiAgICAgICAgICAgICAgICAgZnVucyhtZWFuKC4sIG5hLnJtID0gVFJVRSkpKQogICAgcGxvdCA8LSBkZiAlPiUKICAgIGdncGxvdCgpICsKICAgIGdlb21fc21vb3RoKGFlcyh4ID0gZGYgJT4lIHB1bGwocGFzdGUwKCJzY29yZV8iLCBuKSksIAogICAgICAgICAgICAgICAgICAgIHkgPSBkZiAlPiUgcHVsbChwYXN0ZTAoIm1vdGlmXyIsIG4pKSksCiAgICAgICAgICAgICAgICBmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsbSIsIHNpemUgPSAuMSkgKwogICAgZ2VvbV9wb2ludChhZXMoeCA9IGRmICU+JSBwdWxsKHBhc3RlMCgic2NvcmVfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgIHkgPSBkZiAlPiUgcHVsbChwYXN0ZTAoIm1vdGlmXyIsIG4pKSwgCiAgICAgICAgICAgICAgICAgICBjb2wgPSBjZWxsdHlwZXMsIHNpemUgPSAxKSkgKwogICAgU0NBVFRFUl9USEVNRSArCiAgICAjbGFicyh4ID0gIkdhdGExIGdlbmUgZXhwcmVzc2lvbiIsIHkgPSAiR2F0YTEgbW90aWYgYWNjZXNzaWJpbGl0eSAoei1zY29yZSkiKSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG4pLCB4ID0gImdlbmUgYWN0aXZpdHkgc2NvcmUiLCB5ID0gIlRGLW1vdGlmIHotc2NvcmUiKQogICAgcHJpbnQocGxvdCkKICAgIGdnc2F2ZShwYXN0ZTAocGxvdF9kaXIsICJzY2F0dGVyUGxvdF8iLCBuLCAiLnBkZiIpKQogICAgcHJpbnQocGxvdCkKICAgIH0pCiAgCiAgZG8uY2FsbChncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSwgYyhwbG90cywgc2VhX3Bsb3QsIHNjYXR0ZXJfcGxvdHMsIG5jb2wgPSAyKSkgCiAgIyU+JSBnZ3NhdmUocGFzdGUwKHBsb3RfZGlyLCBuLCAiLnBkZiIpKQoKfQpgYGAKCiMgTWFya2VyIEdlbmVzCgojIyBTRUFDZWxscwoKCmBgYCN7ciwgZmlnLndpZHRoPTYsIGZpZy5oZWlnaHQ9NiwgZXZhbCA9IEZBTFNFfQoKZm9yIChuIGluIG1hcmtlcl9nZW5lcykgewogIHByaW50KG4pCiAgIyBzZWxlY3Qgb25lIHJvdyBmb3IgYSBwYXJ0aWN1bGFyIGdlbmUKICBzY29yZV9uIDwtIGdlbmVfc2NvcmVzX21hdFtyb3duYW1lcyhnZW5lX3Njb3Jlc19tYXQpICVpbiUgYyhuKSwgXQogICMgYWRkIHNjb3JlIGZvciB0aGlzIGdlbmUgdG8gbWV0YWRhdGEKICBtZXRhZGF0YVtwYXN0ZTAoInNjb3JlXyIsbildIDwtIHNjb3JlX24KICAjIHNlbGVjdCBnZW5lIGV4cHJlc3Npb24gZm9yIGEgcGFydGljdWxhciBnZW5lCiAgZXhwcl9uIDwtIGxvZ25vcm1bcm93bmFtZXMobG9nbm9ybSkgJWluJSBjKG4pLCBdCiAgbWV0YWRhdGFbcGFzdGUwKCJleHByXyIsIG4pXSA8LSBleHByX24KICAKICAKICBzZWFjZWxsc19uIDwtIHNlYV9tdHhbcm93bmFtZXMoc2VhX210eCkgPT0gdGZzW2dyZXBsKHBhc3RlMCgiXiIsIG4pLCB0ZnMpXSwgXQogIHNlYV9tZXRhW3Bhc3RlMCgic2VhY2VsbF8iLCBuKV0gPC0gc2VhY2VsbHNfbgoKICAjIGlmIHRoZSBtYXJrZXIgZ2VuZSBpcyBhIFRGCiAgaWYgKGxlbmd0aCh0ZnNbZ3JlcGwocGFzdGUwKCJeIiwgbiksIHRmcyldKSA+IDApIHsKICAgIAogICAgICAjIHNlbGVjdCBtb3RpZiB6IHNjb3JlCiAgICAgIG1vdGlmX24gPC0gbW90aWZfbXR4W3Jvd25hbWVzKG1vdGlmX210eCkgPT0gIHRmc1tncmVwbChwYXN0ZTAoIl4iLCBuKSwgdGZzKV0sIF0KICAgICAgbWV0YWRhdGFbcGFzdGUwKCJtb3RpZl8iLCBuKV0gPC0gbW90aWZfbgogICAgICAKICAgICAgIyBjcmVhdGUgYmFycGxvdHMgZm9yIGdlbmUgc2NvcmVzLCBnZW5lIGV4cHJlc3Npb24gYW5kIG1vdGlmIHotc2NvcmUKICAgICAgcGxvdCA8LSBtYXAoYygic2NvcmVfIiwgIm1vdGlmXyIpLCBmdW5jdGlvbihwKXsKICAgICAgICBkZiA8LSBtZXRhZGF0YSAlPiUKICAgICAgICAgIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lCiAgICAgICAgICBzdW1tYXJpc2VfYXQodmFycyhwYXN0ZTAocCwgbikpLCBmdW5zKG1lYW4oLiwgbmEucm09VFJVRSkpKQogICAgICAgICAgcGxvdCA8LSBkZiAlPiUgZ2dwbG90KCkgKwogICAgICAgICAgZ2VvbV9iYXIoYWVzKHggPSBjZWxsdHlwZXMsIHkgPSBkZiAlPiUgcHVsbChwYXN0ZTAocCwgbikpLCAKICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbCkgKwogICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLAogICAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICAgICAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG4pLCB4ID0gImNlbGx0eXBlIiwgeSA9IHBhc3RlMChwKSkgKwogICAgICAgICAgQkFSX1RIRU1FCiAgICAgICAgcHJpbnQocGxvdCkKICAgICAgICBnZ3NhdmUocGFzdGUwKHBsb3RfZGlyLCBwLCBuLCAiLnBkZiIpKQogICAgICAgIHByaW50KHBsb3QpCiAgICAgIH0pCiAgICAgIAogICAgICAjIGNyZWF0ZSBzY2F0dGVyIHBsb3RzIGZvciBnZW5lIGV4cHJlc3Npb24gYW5kIG1vdGlmIHotc2NvcmUKICAgICAgc2NhdHRlcl9wbG90cyA8LSBtYXAoc2VxLmludCgxKSwgZnVuY3Rpb24ocyl7CiAgICAgICAgZGYgPC0gbWV0YWRhdGEgJT4lIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lIAogICAgICAgIHN1bW1hcmlzZV9hdCh2YXJzKHBhc3RlMCgibW90aWZfIiwgbiksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgic2NvcmVfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgICAgZnVucyhtZWFuKC4sIG5hLnJtID0gVFJVRSkpKQogICAgICAgIHBsb3QgPC0gZGYgJT4lCiAgICAgICAgICBnZ3Bsb3QoKSArCiAgICAgICAgICBnZW9tX3Ntb290aChhZXMoeCA9IGRmICU+JSBwdWxsKHBhc3RlMCgic2NvcmVfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZGYgJT4lIHB1bGwocGFzdGUwKCJtb3RpZl8iLCBuKSkpLAogICAgICAgICAgICAgICAgICAgICAgZm9ybXVsYSA9IHkgfiB4LCBtZXRob2QgPSAibG0iLCBzaXplID0gLjEpICsKICAgICAgICAgIGdlb21fcG9pbnQoYWVzKHggPSBkZiAlPiUgcHVsbChwYXN0ZTAoInNjb3JlXyIsIG4pKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICB5ID0gZGYgJT4lIHB1bGwocGFzdGUwKCJtb3RpZl8iLCBuKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgY29sID0gY2VsbHR5cGVzLCBzaXplID0gMSkpICsKICAgICAgICAgICNsYWJzKHggPSAiR2F0YTEgZ2VuZSBleHByZXNzaW9uIiwgeSA9ICJHYXRhMSBtb3RpZiBhY2Nlc3NpYmlsaXR5ICh6LXNjb3JlKSIpICsKICAgICAgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbCkgKwogICAgICAgICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeCA9ICJnZW5lIGFjdGl2aXR5IHNjb3JlIiwgeSA9ICJURi1tb3RpZiB6LXNjb3JlIikgKwogICAgICAgICAgQkFSX1RIRU1FCiAgICAgICAgcHJpbnQocGxvdCkKICAgICAgICBnZ3NhdmUocGFzdGUwKHBsb3RfZGlyLCAic2NhdHRlclBsb3RfIiwgbiwgIi5wZGYiKSkKICAgICAgICBwcmludChwbG90KQogICAgICB9KQogICAgICAgIHNlYV9wbG90IDwtIG1hcChzZXEuaW50KDEpLCBmdW5jdGlvbihzZWEpewogICAgICAgICAgcGxvdCA8LSBzZWFfbWV0YSAlPiUgCiAgICAgICAgICAgIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lCiAgICAgICAgICAgIHN1bW1hcmlzZShtZWFuID0gbWVhbighIXN5bShwYXN0ZTAoInNlYWNlbGxfIixuKSkpKSAlPiUKICAgICAgICAgICAgZ2dwbG90KCkgKwogICAgICAgICAgICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IG1lYW4sIGZpbGwgPSBjZWxsdHlwZXMpLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICAgICAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLCBsZWdlbmQucG9zaXRpb24gPSAiTm9uZSIpICsjJT4lIHByaW50KCkKICAgICAgICAgICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeSA9ICJTRUFDZWxsIGRldmlhdGlvbiBzY29yZSIpICsKICAgICAgICAgICAgQkFSX1RIRU1FCiAgICAgICAgICBwcmludChwbG90KQogICAgICAgICAgZ2dzYXZlKHBhc3RlMChwbG90X2RpciwgInNlYWNlbGxfYmFyXyIsIG4sICIucGRmIikpCiAgICAgICAgICBwcmludChwbG90KQogICAgICAgICAgCiAgICB9KQogICAgICAKICAgICMgaWYgdGhlIG1hcmtlciBnZW5lIGlzIG5vIFRGCiAgICB9IGVsc2UgewogICAgICBwcmludCgibm8iKQogICAgICAKICAgICAgIyAjIGNyZWF0ZSBiYXJwbG90cyBmb3IgZ2VuZSBzY29yZXMsIGdlbmUgZXhwcmVzc2lvbiBhbmQgbW90aWYgei1zY29yZQogICAgICAjIHBsb3RzIDwtIG1hcChjKCJzY29yZV8iKSwgZnVuY3Rpb24ocCl7CiAgICAgICMgICBkZiA8LSBtZXRhZGF0YSAlPiUKICAgICAgIyAgICAgZ3JvdXBfYnkoY2VsbHR5cGVzKSAlPiUKICAgICAgIyAgICAgc3VtbWFyaXNlX2F0KHZhcnMocGFzdGUwKHAsIG4pKSwgZnVucyhtZWFuKC4sIG5hLnJtPVRSVUUpKSkKICAgICAgIyAgICAgcGxvdCA8LSBkZiAlPiUgZ2dwbG90KCkgKwogICAgICAjICAgICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IGRmICU+JSBwdWxsKHBhc3RlMChwLCBuKSksIAogICAgICAjICAgICAgICAgICAgICAgICAgZmlsbCA9IGNlbGx0eXBlcyksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgICMgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbCkgKwogICAgICAjICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksCiAgICAgICMgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgICAjICAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG4pLCB4ID0gImNlbGx0eXBlIiwgeSA9IHBhc3RlMChwKSkgKwogICAgICAjICAgICBCQVJfVEhFTUUKICAgICAgIyAgIHByaW50KHBsb3QpCiAgICAgICMgICBnZ3NhdmUocGFzdGUwKHBsb3RfZGlyLCBwLCBuLCAiLnBkZiIpKQogICAgICAjICAgcHJpbnQocGxvdCkKICAgICAgIyAKICAgICAgIyB9KQogICAgICAjIAogICAgICAjICMgY3JlYXRlIHNjYXR0ZXIgcGxvdHMgZm9yIGdlbmUgZXhwcmVzc2lvbiBhbmQgZ2VuZV9zY29yZQogICAgICAjIHNjYXR0ZXJfcGxvdHMgPC0gbWFwKHNlcS5pbnQoMSksIGZ1bmN0aW9uKHMpewogICAgICAjICAgZGYgPC0gbWV0YWRhdGEgJT4lIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lCiAgICAgICMgICBzdW1tYXJpc2VfYXQodmFycyhwYXN0ZTAoInNjb3JlXyIsIG4pLAogICAgICAjICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJleHByXyIsIG4pKSwKICAgICAgIyAgICAgICAgICAgICAgICBmdW5zKG1lYW4oLiwgbmEucm0gPSBUUlVFKSkpCiAgICAgICMgICBwbG90IDwtIGRmICU+JQogICAgICAjICAgICBnZ3Bsb3QoKSArCiAgICAgICMgICAgIGdlb21fc21vb3RoKGFlcyh4ID0gZGYgJT4lIHB1bGwocGFzdGUwKCJleHByXyIsIG4pKSwKICAgICAgIyAgICAgICAgICAgICAgICAgICAgIHkgPSBkZiAlPiUgcHVsbChwYXN0ZTAoInNjb3JlXyIsIG4pKSksCiAgICAgICMgICAgICAgICAgICAgICAgIGZvcm11bGEgPSB5IH4geCwgbWV0aG9kID0gImxtIiwgc2l6ZSA9IC4xKSArCiAgICAgICMgICAgIGdlb21fcG9pbnQoYWVzKHggPSBkZiAlPiUgcHVsbChwYXN0ZTAoImV4cHJfIiwgbikpLAogICAgICAjICAgICAgICAgICAgICAgICAgICB5ID0gZGYgJT4lIHB1bGwocGFzdGUwKCJzY29yZV8iLCBuKSksCiAgICAgICMgICAgICAgICAgICAgICAgICAgIGNvbCA9IGNlbGx0eXBlcywgc2l6ZSA9IDEpKSArCiAgICAgICMgICAgICNsYWJzKHggPSAiR2F0YTEgZ2VuZSBleHByZXNzaW9uIiwgeSA9ICJHYXRhMSBtb3RpZiBhY2Nlc3NpYmlsaXR5ICh6LXNjb3JlKSIpICsKICAgICAgIyAgICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICAgICMgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2wpKwogICAgICAjICAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG4pLCB4ID0gImdlbmUgZXhwcmVzc2lvbiIsIHkgPSAiZ2VuZSBhY3Rpdml0eSBzY29yZSIpICsKICAgICAgIyAgICAgQkFSX1RIRU1FCiAgICAgICMgICBwcmludChwbG90KQogICAgICAjICAgZ2dzYXZlKHBhc3RlMChwbG90X2RpciwgInNjYXR0ZXJQbG90XyIsIG4sICIucGRmIikpCiAgICAgICMgICBwcmludChwbG90KQogICAgICAjfSkKICAgIH0KCiAgI2RvLmNhbGwoZ3JpZEV4dHJhOjpncmlkLmFycmFuZ2UsIGMocGxvdHMsIHNjYXR0ZXJfcGxvdHMsIG5jb2wgPSAyLCBucm93ID0gMikpCiAgIyAKCn0KYGBgCgoKIyBEZWVwIGxlYXJuaW5nIG1vdGlmcwoKCmBgYHtyfQpwcm9qMSA8LSBsb2FkQXJjaFJQcm9qZWN0KCIvb21pY3MvZ3JvdXBzL09FMDUzMy9pbnRlcm5hbC9rYXRoYXJpbmEvc2NEb1JJL2dhc3RydWxhdGlvbl9kYXRhX25ldy9LYXRoaS8wNl9kZWVwX2Nocm9tdmFyLyIpCgpkZWVwIDwtIGdldE1hdHJpeEZyb21Qcm9qZWN0KHByb2oxLCB1c2VNYXRyaXggPSAiRGVlcExlYXJuaW5nTW90aWZzMSIpCmRlZXBfbWF0cml4IDwtIGFzc2F5cyhkZWVwKVtbMl1dCgpkZWVwX21hdHJpeCA8LSBkZWVwX21hdHJpeFssIGNvbG5hbWVzKG1vdGlmX210eCldCgpzdG9waWZub3QoYWxsKGNvbG5hbWVzKG1vdGlmX210eCkgPT0gY29sbmFtZXMoZGVlcF9tYXRyaXgpKSkKI3Rlc3QgPC0gcm93bmFtZXMoZGVlcF9tYXRyaXgpCnJvd25hbWVzKGRlZXBfbWF0cml4KSA8LSB0b2xvd2VyKHJvd25hbWVzKGRlZXBfbWF0cml4KSkKc3Vic3RyKHJvd25hbWVzKGRlZXBfbWF0cml4KSwgMSwgMSkgPC0gdG91cHBlcihzdWJzdHIocm93bmFtZXMoZGVlcF9tYXRyaXgpLCAxLCAxKSkKCmBgYAoKCiMgVEZzIG9mIGludGVyZXN0CgpgYGAje3J9Cm1hcmtlcnMgPC0gYygiRWxmNSIsICJQYXgyIiwgIlBheDYiLCAiUGF4MyIsICJQYXg3IiwgIkhveGI5IiwgIkNkeDQiLCAiSG94YTExIiwgIkhveGExMCIsICJUY2YxNSIsIAogICJUYngxIiwgIlRieDYiLCAiTWVzcDIiLCAiTWVzcDEiLCAiUG91ZjUxIiwgIkdhdGExIiwgIkdhdGEyIiwgIkdhdGEzIiwgIkdhdGE0IiwgICJHYXRhNiIsICJTb3gxMCIsCiAgIlNveDExIiAsIlNveDEzIiwiU294MTUiLCJTb3gxNyIgICAgICAKICAsIlNveDIiICwgIlNveDMiLCAiU294MzAiLCAiU294NCIsICJTb3g1IiwgIlNveDYiLCAiU294OSIsICJLbGYxIiwgIktsZjMiLCAiS2xmNCIsICJLbGY1IiwgIktsZjkiICkKCm1hcmtlcnMgPC0gbWFya2Vyc1ttYXJrZXJzICVpbiUgcm93bmFtZXMoZGVlcF9tYXRyaXgpXQoKbWFya2VycyA8LSBtYXJrZXJzW21hcmtlcnMgJWluJSByb3duYW1lcyhnZW5lX3Njb3Jlc19tYXQpXQptYXJrZXJzCmBgYAoKCgoKYGBgI3tyLCBmaWcud2lkdGg9NiwgZmlnLmhlaWdodD02fQpwbG90X2RpciA8LSAgIi9vbWljcy9ncm91cHMvT0UwNTMzL2ludGVybmFsL2thdGhhcmluYS9zY0RvUkkvZ2FzdHJ1bGF0aW9uX2RhdGFfbmV3L0thdGhpL3Bsb3RzL2RlZXBfQ2hyb21WYXIvIgoKZm9yIChuIGluIG1hcmtlcnMpIHsKICBwcmludChuKQogICMgc2VsZWN0IG9uZSByb3cgZm9yIGEgcGFydGljdWxhciBnZW5lCiAgc2NvcmVfbiA8LSBnZW5lX3Njb3Jlc19tYXRbcm93bmFtZXMoZ2VuZV9zY29yZXNfbWF0KSAlaW4lICBuLCBdCiAgIyBhZGQgc2NvcmUgZm9yIHRoaXMgZ2VuZSB0byBtZXRhZGF0YQogIG1ldGFkYXRhW3Bhc3RlMCgic2NvcmVfIixuKV0gPC0gc2NvcmVfbgogICMgc2VsZWN0IGdlbmUgZXhwcmVzc2lvbiBmb3IgYSBwYXJ0aWN1bGFyIGdlbmUKICAjIGV4cHJfbiA8LSBsb2dub3JtW3Jvd25hbWVzKGxvZ25vcm0pICVpbiUgYyhuKSwgXQogICMgbWV0YWRhdGFbcGFzdGUwKCJleHByXyIsIG4pXSA8LSBleHByX24KICAKICAKICAjIHNlYWNlbGxzX24gPC0gc2VhX210eFtyb3duYW1lcyhzZWFfbXR4KSA9PSB0ZnNbZ3JlcGwocGFzdGUwKCJeIiwgbiksIHRmcyldLCBdCiAgIyBzZWFfbWV0YVtwYXN0ZTAoInNlYWNlbGxfIiwgbildIDwtIHNlYWNlbGxzX24KCiAgIyBzZWxlY3QgbW90aWYgeiBzY29yZQogIGRlZXBfbiA8LSBkZWVwX21hdHJpeFtyb3duYW1lcyhkZWVwX21hdHJpeCkgJWluJSBuLCBdCiAgbWV0YWRhdGFbcGFzdGUwKCJkZWVwXyIsIG4pXSA8LSBkZWVwX24KICAKICAjIGNyZWF0ZSBiYXJwbG90cyBmb3IgZ2VuZSBzY29yZXMsIGdlbmUgZXhwcmVzc2lvbiBhbmQgbW90aWYgei1zY29yZQogIHBsb3RzIDwtIG1hcChjKCJzY29yZV8iLCAiZGVlcF8iKSwgZnVuY3Rpb24ocCl7CiAgICBkZiA8LSBtZXRhZGF0YSAlPiUKICAgIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lCiAgICBzdW1tYXJpc2VfYXQodmFycyhwYXN0ZTAocCwgbikpLCBmdW5zKG1lYW4oLiwgbmEucm09VFJVRSkpKQogICAgcGxvdCA8LSBkZiAlPiUgZ2dwbG90KCkgKwogICAgZ2VvbV9iYXIoYWVzKHggPSBjZWxsdHlwZXMsIHkgPSBkZiAlPiUgcHVsbChwYXN0ZTAocCwgbikpLCAKICAgICAgICAgICAgICAgICBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGNvbCkgKwogICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeCA9ICJjZWxsdHlwZSIsIHkgPSBwYXN0ZTAocCkpICsKICAgIEJBUl9USEVNRQogICAgcHJpbnQocGxvdCkKICAgIGdnc2F2ZShwYXN0ZTAocGxvdF9kaXIsICBwLCBuLCAiLnBkZiIpKQogICAgcHJpbnQocGxvdCkKICB9KQogICAgc2NhdHRlcl9wbG90cyA8LSBtYXAoc2VxLmludCgxKSwgZnVuY3Rpb24ocyl7CiAgICBkZiA8LSBtZXRhZGF0YSAlPiUgZ3JvdXBfYnkoY2VsbHR5cGVzKSAlPiUgCiAgICBzdW1tYXJpc2VfYXQodmFycyhwYXN0ZTAoImRlZXBfIiwgbiksIAogICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJzY29yZV8iLCBuKSksIAogICAgICAgICAgICAgICAgIGZ1bnMobWVhbiguLCBuYS5ybSA9IFRSVUUpKSkKICAgIHBsb3QgPC0gZGYgJT4lCiAgICBnZ3Bsb3QoKSArCiAgICBnZW9tX3Ntb290aChhZXMoeCA9IGRmICU+JSBwdWxsKHBhc3RlMCgic2NvcmVfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgICB5ID0gZGYgJT4lIHB1bGwocGFzdGUwKCJkZWVwXyIsIG4pKSksCiAgICAgICAgICAgICAgICBmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsbSIsIHNpemUgPSAuMSkgKwogICAgZ2VvbV9wb2ludChhZXMoeCA9IGRmICU+JSBwdWxsKHBhc3RlMCgic2NvcmVfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgIHkgPSBkZiAlPiUgcHVsbChwYXN0ZTAoImRlZXBfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgIGNvbCA9IGNlbGx0eXBlcywgc2l6ZSA9IDEpKSArCiAgICBTQ0FUVEVSX1RIRU1FICsKICAgICNsYWJzKHggPSAiR2F0YTEgZ2VuZSBleHByZXNzaW9uIiwgeSA9ICJHYXRhMSBtb3RpZiBhY2Nlc3NpYmlsaXR5ICh6LXNjb3JlKSIpICsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICAgIGxhYnModGl0bGUgPSBwYXN0ZTAobiksIHggPSAiZ2VuZSBhY3Rpdml0eSBzY29yZSIsIHkgPSAiVEYtbW90aWYgei1zY29yZSAoZGVlcCBsZWFybmluZykiKQogICAgcHJpbnQocGxvdCkKICAgIGdnc2F2ZShwYXN0ZTAocGxvdF9kaXIsICJzY2F0dGVyUGxvdF8iLCBuLCAiLnBkZiIpKQogICAgcHJpbnQocGxvdCkKICAgIH0pCiAgCiAgCiAgCiAgZG8uY2FsbChncmlkRXh0cmE6OmdyaWQuYXJyYW5nZSwgYyhwbG90cywgc2VhX3Bsb3QsIHNjYXR0ZXJfcGxvdHMsIG5jb2wgPSAyKSkgCiAgIyU+JSBnZ3NhdmUocGFzdGUwKHBsb3RfZGlyLCBuLCAiLnBkZiIpKQoKfQpgYGAKCgpgYGAje3J9CmZvciAobiBpbiBtYXJrZXJfZ2VuZXMpIHsKICBwcmludChuKQogICMgc2VsZWN0IG9uZSByb3cgZm9yIGEgcGFydGljdWxhciBnZW5lCiAgc2NvcmVfbiA8LSBnZW5lX3Njb3Jlc19tYXRbcm93bmFtZXMoZ2VuZV9zY29yZXNfbWF0KSAlaW4lIGMobiksIF0KICAjIGFkZCBzY29yZSBmb3IgdGhpcyBnZW5lIHRvIG1ldGFkYXRhCiAgbWV0YWRhdGFbcGFzdGUwKCJzY29yZV8iLG4pXSA8LSBzY29yZV9uCiAgIyBzZWxlY3QgZ2VuZSBleHByZXNzaW9uIGZvciBhIHBhcnRpY3VsYXIgZ2VuZQogIGV4cHJfbiA8LSBsb2dub3JtW3Jvd25hbWVzKGxvZ25vcm0pICVpbiUgYyhuKSwgXQogIG1ldGFkYXRhW3Bhc3RlMCgiZXhwcl8iLCBuKV0gPC0gZXhwcl9uCiAgCiAgCiAgc2VhY2VsbHNfbiA8LSBzZWFfbXR4W3Jvd25hbWVzKHNlYV9tdHgpID09IHRmc1tncmVwbChwYXN0ZTAoIl4iLCBuKSwgdGZzKV0sIF0KICBzZWFfbWV0YVtwYXN0ZTAoInNlYWNlbGxfIiwgbildIDwtIHNlYWNlbGxzX24KCiAgIyBpZiB0aGUgbWFya2VyIGdlbmUgaXMgYSBURgogIGlmIChsZW5ndGgodGZzW2dyZXBsKHBhc3RlMCgiXiIsIG4pLCB0ZnMpXSkgPiAwKSB7CiAgICAKICAgICAgIyBzZWxlY3QgbW90aWYgeiBzY29yZQogICAgICBtb3RpZl9uIDwtIG1vdGlmX210eFtyb3duYW1lcyhtb3RpZl9tdHgpID09ICB0ZnNbZ3JlcGwocGFzdGUwKCJeIiwgbiksIHRmcyldLCBdCiAgICAgIG1ldGFkYXRhW3Bhc3RlMCgibW90aWZfIiwgbildIDwtIG1vdGlmX24KICAgICAgCiAgICAgICMgY3JlYXRlIGJhcnBsb3RzIGZvciBnZW5lIHNjb3JlcywgZ2VuZSBleHByZXNzaW9uIGFuZCBtb3RpZiB6LXNjb3JlCiAgICAgIHBsb3QgPC0gbWFwKGMoInNjb3JlXyIsICJtb3RpZl8iKSwgZnVuY3Rpb24ocCl7CiAgICAgICAgZGYgPC0gbWV0YWRhdGEgJT4lCiAgICAgICAgICBncm91cF9ieShjZWxsdHlwZXMpICU+JQogICAgICAgICAgc3VtbWFyaXNlX2F0KHZhcnMocGFzdGUwKHAsIG4pKSwgZnVucyhtZWFuKC4sIG5hLnJtPVRSVUUpKSkKICAgICAgICAgIHBsb3QgPC0gZGYgJT4lIGdncGxvdCgpICsKICAgICAgICAgIGdlb21fYmFyKGFlcyh4ID0gY2VsbHR5cGVzLCB5ID0gZGYgJT4lIHB1bGwocGFzdGUwKHAsIG4pKSwgCiAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9IGNlbGx0eXBlcyksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSwKICAgICAgICAgICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgICAgICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeCA9ICJjZWxsdHlwZSIsIHkgPSBwYXN0ZTAocCkpICsKICAgICAgICAgIEJBUl9USEVNRQogICAgICAgIHByaW50KHBsb3QpCiAgICAgICAgZ2dzYXZlKHBhc3RlMChwbG90X2RpciwgcCwgbiwgIi5wZGYiKSkKICAgICAgICBwcmludChwbG90KQogICAgICB9KQogICAgICAKICAgICAgIyBjcmVhdGUgc2NhdHRlciBwbG90cyBmb3IgZ2VuZSBleHByZXNzaW9uIGFuZCBtb3RpZiB6LXNjb3JlCiAgICAgIHNjYXR0ZXJfcGxvdHMgPC0gbWFwKHNlcS5pbnQoMSksIGZ1bmN0aW9uKHMpewogICAgICAgIGRmIDwtIG1ldGFkYXRhICU+JSBncm91cF9ieShjZWxsdHlwZXMpICU+JSAKICAgICAgICBzdW1tYXJpc2VfYXQodmFycyhwYXN0ZTAoIm1vdGlmXyIsIG4pLCAKICAgICAgICAgICAgICAgICAgICAgICAgICBwYXN0ZTAoInNjb3JlXyIsIG4pKSwgCiAgICAgICAgICAgICAgICAgICAgIGZ1bnMobWVhbiguLCBuYS5ybSA9IFRSVUUpKSkKICAgICAgICBwbG90IDwtIGRmICU+JQogICAgICAgICAgZ2dwbG90KCkgKwogICAgICAgICAgZ2VvbV9zbW9vdGgoYWVzKHggPSBkZiAlPiUgcHVsbChwYXN0ZTAoInNjb3JlXyIsIG4pKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRmICU+JSBwdWxsKHBhc3RlMCgibW90aWZfIiwgbikpKSwKICAgICAgICAgICAgICAgICAgICAgIGZvcm11bGEgPSB5IH4geCwgbWV0aG9kID0gImxtIiwgc2l6ZSA9IC4xKSArCiAgICAgICAgICBnZW9tX3BvaW50KGFlcyh4ID0gZGYgJT4lIHB1bGwocGFzdGUwKCJzY29yZV8iLCBuKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRmICU+JSBwdWxsKHBhc3RlMCgibW90aWZfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGNvbCA9IGNlbGx0eXBlcywgc2l6ZSA9IDEpKSArCiAgICAgICAgICAjbGFicyh4ID0gIkdhdGExIGdlbmUgZXhwcmVzc2lvbiIsIHkgPSAiR2F0YTEgbW90aWYgYWNjZXNzaWJpbGl0eSAoei1zY29yZSkiKSArCiAgICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICAgICAgICAgIGxhYnModGl0bGUgPSBwYXN0ZTAobiksIHggPSAiZ2VuZSBhY3Rpdml0eSBzY29yZSIsIHkgPSAiVEYtbW90aWYgei1zY29yZSIpICsKICAgICAgICAgIEJBUl9USEVNRQogICAgICAgIHByaW50KHBsb3QpCiAgICAgICAgZ2dzYXZlKHBhc3RlMChwbG90X2RpciwgInNjYXR0ZXJQbG90XyIsIG4sICIucGRmIikpCiAgICAgICAgcHJpbnQocGxvdCkKICAgICAgfSkKICAgICAgICBzZWFfcGxvdCA8LSBtYXAoc2VxLmludCgxKSwgZnVuY3Rpb24oc2VhKXsKICAgICAgICAgIHBsb3QgPC0gc2VhX21ldGEgJT4lIAogICAgICAgICAgICBncm91cF9ieShjZWxsdHlwZXMpICU+JQogICAgICAgICAgICBzdW1tYXJpc2UobWVhbiA9IG1lYW4oISFzeW0ocGFzdGUwKCJzZWFjZWxsXyIsbikpKSkgJT4lCiAgICAgICAgICAgIGdncGxvdCgpICsKICAgICAgICAgICAgZ2VvbV9iYXIoYWVzKHggPSBjZWxsdHlwZXMsIHkgPSBtZWFuLCBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICAgICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIHZqdXN0ID0gMC41LCBoanVzdD0xKSwgbGVnZW5kLnBvc2l0aW9uID0gIk5vbmUiKSArIyU+JSBwcmludCgpCiAgICAgICAgICAgIGxhYnModGl0bGUgPSBwYXN0ZTAobiksIHkgPSAiU0VBQ2VsbCBkZXZpYXRpb24gc2NvcmUiKSArCiAgICAgICAgICAgIEJBUl9USEVNRQogICAgICAgICAgcHJpbnQocGxvdCkKICAgICAgICAgIGdnc2F2ZShwYXN0ZTAocGxvdF9kaXIsICJzZWFjZWxsX2Jhcl8iLCBuLCAiLnBkZiIpKQogICAgICAgICAgcHJpbnQocGxvdCkKICAgICAgICAgIAogICAgfSkKICAgICAgCiAgICAjIGlmIHRoZSBtYXJrZXIgZ2VuZSBpcyBubyBURgogICAgfSBlbHNlIHsKICAgICAgcHJpbnQoIm5vIikKICAgICAgCiAgICAgICMgIyBjcmVhdGUgYmFycGxvdHMgZm9yIGdlbmUgc2NvcmVzLCBnZW5lIGV4cHJlc3Npb24gYW5kIG1vdGlmIHotc2NvcmUKICAgICAgIyBwbG90cyA8LSBtYXAoYygic2NvcmVfIiksIGZ1bmN0aW9uKHApewogICAgICAjICAgZGYgPC0gbWV0YWRhdGEgJT4lCiAgICAgICMgICAgIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lCiAgICAgICMgICAgIHN1bW1hcmlzZV9hdCh2YXJzKHBhc3RlMChwLCBuKSksIGZ1bnMobWVhbiguLCBuYS5ybT1UUlVFKSkpCiAgICAgICMgICAgIHBsb3QgPC0gZGYgJT4lIGdncGxvdCgpICsKICAgICAgIyAgICAgZ2VvbV9iYXIoYWVzKHggPSBjZWxsdHlwZXMsIHkgPSBkZiAlPiUgcHVsbChwYXN0ZTAocCwgbikpLCAKICAgICAgIyAgICAgICAgICAgICAgICAgIGZpbGwgPSBjZWxsdHlwZXMpLCBzdGF0ID0gImlkZW50aXR5IikgKwogICAgICAjICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICAgICAgIyAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLAogICAgICAjICAgICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgICAgIyAgICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeCA9ICJjZWxsdHlwZSIsIHkgPSBwYXN0ZTAocCkpICsKICAgICAgIyAgICAgQkFSX1RIRU1FCiAgICAgICMgICBwcmludChwbG90KQogICAgICAjICAgZ2dzYXZlKHBhc3RlMChwbG90X2RpciwgcCwgbiwgIi5wZGYiKSkKICAgICAgIyAgIHByaW50KHBsb3QpCiAgICAgICMgCiAgICAgICMgfSkKICAgICAgIyAKICAgICAgIyAjIGNyZWF0ZSBzY2F0dGVyIHBsb3RzIGZvciBnZW5lIGV4cHJlc3Npb24gYW5kIGdlbmVfc2NvcmUKICAgICAgIyBzY2F0dGVyX3Bsb3RzIDwtIG1hcChzZXEuaW50KDEpLCBmdW5jdGlvbihzKXsKICAgICAgIyAgIGRmIDwtIG1ldGFkYXRhICU+JSBncm91cF9ieShjZWxsdHlwZXMpICU+JQogICAgICAjICAgc3VtbWFyaXNlX2F0KHZhcnMocGFzdGUwKCJzY29yZV8iLCBuKSwKICAgICAgIyAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgiZXhwcl8iLCBuKSksCiAgICAgICMgICAgICAgICAgICAgICAgZnVucyhtZWFuKC4sIG5hLnJtID0gVFJVRSkpKQogICAgICAjICAgcGxvdCA8LSBkZiAlPiUKICAgICAgIyAgICAgZ2dwbG90KCkgKwogICAgICAjICAgICBnZW9tX3Ntb290aChhZXMoeCA9IGRmICU+JSBwdWxsKHBhc3RlMCgiZXhwcl8iLCBuKSksCiAgICAgICMgICAgICAgICAgICAgICAgICAgICB5ID0gZGYgJT4lIHB1bGwocGFzdGUwKCJzY29yZV8iLCBuKSkpLAogICAgICAjICAgICAgICAgICAgICAgICBmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsbSIsIHNpemUgPSAuMSkgKwogICAgICAjICAgICBnZW9tX3BvaW50KGFlcyh4ID0gZGYgJT4lIHB1bGwocGFzdGUwKCJleHByXyIsIG4pKSwKICAgICAgIyAgICAgICAgICAgICAgICAgICAgeSA9IGRmICU+JSBwdWxsKHBhc3RlMCgic2NvcmVfIiwgbikpLAogICAgICAjICAgICAgICAgICAgICAgICAgICBjb2wgPSBjZWxsdHlwZXMsIHNpemUgPSAxKSkgKwogICAgICAjICAgICAjbGFicyh4ID0gIkdhdGExIGdlbmUgZXhwcmVzc2lvbiIsIHkgPSAiR2F0YTEgbW90aWYgYWNjZXNzaWJpbGl0eSAoei1zY29yZSkiKSArCiAgICAgICMgICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikgKwogICAgICAjICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sKSsKICAgICAgIyAgICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeCA9ICJnZW5lIGV4cHJlc3Npb24iLCB5ID0gImdlbmUgYWN0aXZpdHkgc2NvcmUiKSArCiAgICAgICMgICAgIEJBUl9USEVNRQogICAgICAjICAgcHJpbnQocGxvdCkKICAgICAgIyAgIGdnc2F2ZShwYXN0ZTAocGxvdF9kaXIsICJzY2F0dGVyUGxvdF8iLCBuLCAiLnBkZiIpKQogICAgICAjICAgcHJpbnQocGxvdCkKICAgICAgI30pCiAgICB9CgogICNkby5jYWxsKGdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlLCBjKHBsb3RzLCBzY2F0dGVyX3Bsb3RzLCBuY29sID0gMiwgbnJvdyA9IDIpKQogICMgCgp9CmBgYAoKClBsb3QgZ2VuZSBleHByZXNzaW9uLCBnZW5lIHNjb3JlcyAmIG1vdGlmIHotc2NvcmVzOgoKYGBgI3tyLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9MTB9Cgpmb3IgKG4gaW4gbWFya2VyX2dlbmVzKSB7CiAgcHJpbnQobikKICAjIHNlbGVjdCBvbmUgcm93IGZvciBhIHBhcnRpY3VsYXIgZ2VuZQogIHNjb3JlX24gPC0gZ2VuZV9zY29yZXNfbWF0W3Jvd25hbWVzKGdlbmVfc2NvcmVzX21hdCkgJWluJSBjKG4pLCBdCiAgIyBhZGQgc2NvcmUgZm9yIHRoaXMgZ2VuZSB0byBtZXRhZGF0YQogIG1ldGFkYXRhW3Bhc3RlMCgic2NvcmVfIixuKV0gPC0gc2NvcmVfbgogICMgc2VsZWN0IGdlbmUgZXhwcmVzc2lvbiBmb3IgYSBwYXJ0aWN1bGFyIGdlbmUKICBleHByX24gPC0gbG9nbm9ybVtyb3duYW1lcyhsb2dub3JtKSAlaW4lIGMobiksIF0KICBtZXRhZGF0YVtwYXN0ZTAoImV4cHJfIiwgbildIDwtIGV4cHJfbgogIAogIAogIHNlYWNlbGxzX24gPC0gc2VhX210eFtyb3duYW1lcyhzZWFfbXR4KSA9PSB0ZnNbZ3JlcGwocGFzdGUwKCJeIiwgbiksIHRmcyldLCBdCiAgc2VhX21ldGFbcGFzdGUwKCJzZWFjZWxsXyIsIG4pXSA8LSBzZWFjZWxsc19uCgogICMgaWYgdGhlIG1hcmtlciBnZW5lIGlzIGEgVEYKICBpZiAobGVuZ3RoKHRmc1tncmVwbChwYXN0ZTAoIl4iLCBuKSwgdGZzKV0pID4gMCkgewogICAgCiAgICAgICMgc2VsZWN0IG1vdGlmIHogc2NvcmUKICAgICAgbW90aWZfbiA8LSBtb3RpZl9tdHhbcm93bmFtZXMobW90aWZfbXR4KSA9PSAgdGZzW2dyZXBsKHBhc3RlMCgiXiIsIG4pLCB0ZnMpXSwgXQogICAgICBtZXRhZGF0YVtwYXN0ZTAoIm1vdGlmXyIsIG4pXSA8LSBtb3RpZl9uCiAgICAgIAogICAgICAjIGNyZWF0ZSBiYXJwbG90cyBmb3IgZ2VuZSBzY29yZXMsIGdlbmUgZXhwcmVzc2lvbiBhbmQgbW90aWYgei1zY29yZQogICAgICBwbG90cyA8LSBtYXAoYygic2NvcmVfIiwgImV4cHJfIiwgIm1vdGlmXyIpLCBmdW5jdGlvbihwKXsKICAgICAgICBkZiA8LSBtZXRhZGF0YSAlPiUKICAgICAgICBncm91cF9ieShjZWxsdHlwZXMpICU+JQogICAgICAgIHN1bW1hcmlzZV9hdCh2YXJzKHBhc3RlMChwLCBuKSksIGZ1bnMobWVhbiguLCBuYS5ybT1UUlVFKSkpCiAgICAgICAgZGYgJT4lIGdncGxvdCgpICsKICAgICAgICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IGRmICU+JSBwdWxsKHBhc3RlMChwLCBuKSksIAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICAgICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeCA9ICJjZWxsdHlwZSIsIHkgPSBwYXN0ZTAocCkpCiAgICAgIH0pCiAgICAgIAogICAgICAjIGNyZWF0ZSBzY2F0dGVyIHBsb3RzIGZvciBnZW5lIGV4cHJlc3Npb24gYW5kIG1vdGlmIHotc2NvcmUKICAgICAgc2NhdHRlcl9wbG90cyA8LSBtYXAoc2VxLmludCgxKSwgZnVuY3Rpb24ocyl7CiAgICAgICAgZGYgPC0gbWV0YWRhdGEgJT4lIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lIAogICAgICAgIHN1bW1hcmlzZV9hdCh2YXJzKHBhc3RlMCgibW90aWZfIiwgbiksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCgic2NvcmVfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgICAgZnVucyhtZWFuKC4sIG5hLnJtID0gVFJVRSkpKQogICAgICAgIGRmICU+JQogICAgICAgIGdncGxvdCgpICsKICAgICAgICBnZW9tX3Ntb290aChhZXMoeCA9IGRmICU+JSBwdWxsKHBhc3RlMCgic2NvcmVfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRmICU+JSBwdWxsKHBhc3RlMCgibW90aWZfIiwgbikpKSwKICAgICAgICAgICAgICAgICAgICBmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsbSIsIHNpemUgPSAuMSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKHggPSBkZiAlPiUgcHVsbChwYXN0ZTAoInNjb3JlXyIsIG4pKSwgCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRmICU+JSBwdWxsKHBhc3RlMCgibW90aWZfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBjZWxsdHlwZXMsIHNpemUgPSAxKSkgKwogICAgICAgICNsYWJzKHggPSAiR2F0YTEgZ2VuZSBleHByZXNzaW9uIiwgeSA9ICJHYXRhMSBtb3RpZiBhY2Nlc3NpYmlsaXR5ICh6LXNjb3JlKSIpICsKICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sKSArCiAgICAgICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeCA9ICJnZW5lIGFjdGl2aXR5IHNjb3JlIiwgeSA9ICJURi1tb3RpZiB6LXNjb3JlIikKICAgICAgICB9KQogICAgICAKICAgICMgaWYgdGhlIG1hcmtlciBnZW5lIGlzIG5vIFRGCiAgICB9IGVsc2UgewogICAgICAKICAgICAgIyBjcmVhdGUgYmFycGxvdHMgZm9yIGdlbmUgc2NvcmVzLCBnZW5lIGV4cHJlc3Npb24gYW5kIG1vdGlmIHotc2NvcmUKICAgICAgcGxvdHMgPC0gbWFwKGMoInNjb3JlXyIsICJleHByXyIpLCBmdW5jdGlvbihwKXsKICAgICAgICBkZiA8LSBtZXRhZGF0YSAlPiUKICAgICAgICBncm91cF9ieShjZWxsdHlwZXMpICU+JQogICAgICAgIHN1bW1hcmlzZV9hdCh2YXJzKHBhc3RlMChwLCBuKSksIGZ1bnMobWVhbiguLCBuYS5ybT1UUlVFKSkpCiAgICAgICAgZGYgJT4lIGdncGxvdCgpICsKICAgICAgICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IGRmICU+JSBwdWxsKHBhc3RlMChwLCBuKSksIAogICAgICAgICAgICAgICAgICAgICBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksCiAgICAgICAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgICAgICAgbGFicyh0aXRsZSA9IHBhc3RlMChuKSwgeCA9ICJjZWxsdHlwZSIsIHkgPSBwYXN0ZTAocCkpCgogICAgICB9KQogICAgICAKICAgICAgIyBjcmVhdGUgc2NhdHRlciBwbG90cyBmb3IgZ2VuZSBleHByZXNzaW9uIGFuZCBnZW5lX3Njb3JlCiAgICAgIHNjYXR0ZXJfcGxvdHMgPC0gbWFwKHNlcS5pbnQoMSksIGZ1bmN0aW9uKHMpewogICAgICAgIGRmIDwtIG1ldGFkYXRhICU+JSBncm91cF9ieShjZWxsdHlwZXMpICU+JQogICAgICAgIHN1bW1hcmlzZV9hdCh2YXJzKHBhc3RlMCgic2NvcmVfIiwgbiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgcGFzdGUwKCJleHByXyIsIG4pKSwKICAgICAgICAgICAgICAgICAgICAgZnVucyhtZWFuKC4sIG5hLnJtID0gVFJVRSkpKSAKICAgICAgICBkZiAlPiUKICAgICAgICBnZ3Bsb3QoKSArCiAgICAgICAgZ2VvbV9zbW9vdGgoYWVzKHggPSBkZiAlPiUgcHVsbChwYXN0ZTAoImV4cHJfIiwgbikpLCAKICAgICAgICAgICAgICAgICAgICAgICAgeSA9IGRmICU+JSBwdWxsKHBhc3RlMCgic2NvcmVfIiwgbikpKSwKICAgICAgICAgICAgICAgICAgICBmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsbSIsIHNpemUgPSAuMSkgKwogICAgICAgIGdlb21fcG9pbnQoYWVzKHggPSBkZiAlPiUgcHVsbChwYXN0ZTAoImV4cHJfIiwgbikpLAogICAgICAgICAgICAgICAgICAgICAgIHkgPSBkZiAlPiUgcHVsbChwYXN0ZTAoInNjb3JlXyIsIG4pKSwKICAgICAgICAgICAgICAgICAgICAgICBjb2wgPSBjZWxsdHlwZXMsIHNpemUgPSAxKSkgKwogICAgICAgICNsYWJzKHggPSAiR2F0YTEgZ2VuZSBleHByZXNzaW9uIiwgeSA9ICJHYXRhMSBtb3RpZiBhY2Nlc3NpYmlsaXR5ICh6LXNjb3JlKSIpICsKICAgICAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sKSsKICAgICAgICBsYWJzKHRpdGxlID0gcGFzdGUwKG4pLCB4ID0gImdlbmUgZXhwcmVzc2lvbiIsIHkgPSAiZ2VuZSBhY3Rpdml0eSBzY29yZSIpCgogICAgICB9KQogICAgfQoKICBkby5jYWxsKGdyaWRFeHRyYTo6Z3JpZC5hcnJhbmdlLCBjKHBsb3RzLCBzY2F0dGVyX3Bsb3RzLCBuY29sID0gMiwgbnJvdyA9IDIpKQogICMgCgp9CmBgYAoKCgpgYGAje3IsIGZpZy53aWR0aD0xMCwgZmlnLmhlaWdodD0xMH0KcDEgPC0gbWV0YWRhdGEgJT4lCiAgZ3JvdXBfYnkoY2VsbHR5cGVzKSAlPiUKICBzdW1tYXJpc2VfYXQodmFycyhHYXRhMSksIGZ1bnMobWVkaWFuKC4sIG5hLnJtPVRSVUUpKSkgJT4lIGdncGxvdCgpICsKICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IEdhdGExLCBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCnAyIDwtIG1ldGFkYXRhICU+JQogIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lCiAgc3VtbWFyaXNlX2F0KHZhcnMoZ2F0YTFfc2NvcmVfcDJnKSwgZnVucyhtZWFuKC4sIG5hLnJtPVRSVUUpKSkgJT4lIGdncGxvdCgpICsKICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IGdhdGExX3Njb3JlX3AyZywgZmlsbCA9IGNlbGx0eXBlcyksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLCAKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgoKcDMgPC0gbWV0YWRhdGEgJT4lIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lIAogIHN1bW1hcmlzZV9hdCh2YXJzKGdhdGExX3pfc2NvcmVzLCBHYXRhMSksIGZ1bnMobWVhbiguLCBuYS5ybSA9IFRSVUUpKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc21vb3RoKGFlcyh4ID0gR2F0YTEsIHkgPSBnYXRhMV96X3Njb3JlcyksIGZvcm11bGEgPSB5IH4geCwgbWV0aG9kID0gImxtIiwgc2l6ZSA9IC4xKSArCiAgZ2VvbV9wb2ludChhZXMoeCA9IEdhdGExLCB5ID0gZ2F0YTFfel9zY29yZXMsIGNvbCA9IGNlbGx0eXBlcywgc2l6ZSA9IDEpKSArCiAgbGFicyh4ID0gIkdhdGExIGdlbmUgZXhwcmVzc2lvbiIsIHkgPSAiR2F0YTEgbW90aWYgYWNjZXNzaWJpbGl0eSAoei1zY29yZSkiKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbCkgCgpwNCA8LSBtZXRhZGF0YSAlPiUKICBncm91cF9ieShjZWxsdHlwZXMpICU+JQogIHN1bW1hcmlzZV9hdCh2YXJzKGdhdGExX3pfc2NvcmVzKSwgZnVucyhtZWFuKC4sIG5hLnJtPVRSVUUpKSkgJT4lIGdncGxvdCgpICsKICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IGdhdGExX3pfc2NvcmVzLCBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCmNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIHAzLCBwNCkKCnAxIDwtIG1ldGFkYXRhICU+JQogIGdyb3VwX2J5KGNlbGx0eXBlcykgJT4lCiAgc3VtbWFyaXNlX2F0KHZhcnMoU294OSksIGZ1bnMobWVhbiguLCBuYS5ybT1UUlVFKSkpICU+JSBnZ3Bsb3QoKSArCiAgZ2VvbV9iYXIoYWVzKHggPSBjZWxsdHlwZXMsIHkgPSBTb3g5LCBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKQoKCgpwMiA8LSBtZXRhZGF0YSAlPiUKICBncm91cF9ieShjZWxsdHlwZXMpICU+JQogIHN1bW1hcmlzZV9hdCh2YXJzKHNveDlfel9zY29yZXMpLCBmdW5zKG1lYW4oLiwgbmEucm09VFJVRSkpKSAlPiUgZ2dwbG90KCkgKwogIGdlb21fYmFyKGFlcyh4ID0gY2VsbHR5cGVzLCB5ID0gc294OV96X3Njb3JlcywgZmlsbCA9IGNlbGx0eXBlcyksIHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gY29sKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0PTEpLCAKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpCgpwMyA8LSBtZXRhZGF0YSAlPiUKICBncm91cF9ieShjZWxsdHlwZXMpICU+JQogIHN1bW1hcmlzZV9hdCh2YXJzKHNveDlfc2NvcmVfcDJnKSwgZnVucyhtZWFuKC4sIG5hLnJtPVRSVUUpKSkgJT4lIGdncGxvdCgpICsKICBnZW9tX2JhcihhZXMoeCA9IGNlbGx0eXBlcywgeSA9IHNveDlfc2NvcmVfcDJnLCBmaWxsID0gY2VsbHR5cGVzKSwgc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjb2wpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3Q9MSksIAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikKCgpwNCA8LSBtZXRhZGF0YSAlPiUgZ3JvdXBfYnkoY2VsbHR5cGVzKSAlPiUgCiAgc3VtbWFyaXNlX2F0KHZhcnMoc294OV96X3Njb3JlcywgU294OSksIGZ1bnMobWVhbiguLCBuYS5ybSA9IFRSVUUpKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc21vb3RoKGFlcyh4ID0gU294OSwgeSA9IHNveDlfel9zY29yZXMpLCBmb3JtdWxhID0geSB+IHgsIG1ldGhvZCA9ICJsbSIsIHNpemUgPSAuMSkgKwogIGdlb21fcG9pbnQoYWVzKHggPSBTb3g5LCB5ID0gc294OV96X3Njb3JlcywgY29sID0gY2VsbHR5cGVzLCBzaXplID0gMSkpICsKICBsYWJzKHggPSAiR2F0YTEgZ2VuZSBleHByZXNzaW9uIiwgeSA9ICJHYXRhMSBtb3RpZiBhY2Nlc3NpYmlsaXR5ICh6LXNjb3JlKSIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpICsKICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sKSAKCmNvd3Bsb3Q6OnBsb3RfZ3JpZChwMSwgcDIsIHAzLCBwNCkKCmBgYAoKCgoKCgo=